I'm developing a webapp on Liferay with JSF Primefaces. I have Portlet 1 and Portlet 2 on the same page. I wish to update a component on the UI in the Portlet 1 after a button is clicked in Portlet 2.
I have used the method as follows in Portlet 2:
public void sendEvent(String viewId){
FacesContext fc = FacesContext.getCurrentInstance();
Object obj = fc.getExternalContext().getResponse();
if (obj instanceof ActionResponse){
ActionResponse ar = (ActionResponse) obj;
ar.setEvent
(new QName("http://oracle.com/sampleEvents",
"display.change"),
myId);
}
}
Listening to the event in Portlet 1:
@Override
public void processEvent(EventRequest eRequest, EventResponse eResponse) {
log.info("processEvent, event {} has been arrived", eRequest.getEvent());
MyService myService = CDILookup.getBeanByClass(MyService.class);
myService.updateStuff(eRequest.getEvent().getValue().toString());
}
It works like a charm.
I have thow following command link in my XHTML (Portlet 2):
<ui:fragment rendered="#{ifSo()}">
<div class="myClass" id="#{uuid}_mark_stuff"
onclick="rmc_mark_my_stuff([{name:'id', value:'#{uuid}'}]);">
<h:commandLink actionListener="#{myBean.sendChangeEvent('aaa')}">
<icon icon="myIcon"/>
</h:commandLink>
</div>
</ui:fragment>
The problem is that after the commandLink gets called the whole page refresh altough I only need a refresh in my Portlet 1, but not in Portlet 2. I have tried a lot of stuffs already but no success.
When I change the command link then my Response cannot be casted to ActionResponse to send the event. When I try event.preventDefault
to prevent the refresh, my event does not get fired at all. If I add any JS methods then the ActionResponse issue comes again.
Any idea? Or is it just like that and cannot work so?
I have also tried adding:
<script>
function myFireEvent(caller, value) {
var payload = ...; // process your parameters
Liferay.fire('my-event-name', {
payload: payload
});
return false;
};
</script>
but since I use only XHTML pages, the method cannot be called, Liferay is missing.
Thank you for your help in advance!
The portlet IPC specification is from JSR-286, which dates back to a time when whole page requests were the way to go (2008) and single-page-applications were unheard of (at least under this name). Also, Portlet-IPC is purely specified on server-side, so I don't expect anything available on JS unless you manually trigger a portlet action (which implies a full page reload).
Relying on this technique - I'm afraid - ties you to its assumptions about the world. Liferay's SPA implementation (Senna) might help you by staying more in context, but at least in the background, a whole page refresh is inevitable. Adding JSF and its portlet bridge to the equation does not make it easier.
According to the specification, during a portlet's render phase, no more state can change - this includes events being sent or received. That's why it's impossible to convert a render-request to an action-request or other. Messing with that assumption - in case you find a workaround - is so far into the unspecified realm, that you can't assume that it'll continue to work.
That being said, I'm sure that either JSF or manual triggers of resource-requests to the portlets would allow you to solve the problem and communicate updates. It's just not fully automated as you seem to expect.