jsfliferayipc

Not to update form after IPC


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!


Solution

  • 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.