I'm developing a webapp on Liferay 6.2 with JSF Primefaces 5.3. The webapp runs on Tomcat. I have Portlet 1 and Portlet 2 on the same page. I want to set the state of some back-end object that belongs to Portlet 1 after the user interacts with controls in Portlet 2.
I tried an event-based solution, which works just fine. On my view.xhtml I have something like this:
<p:selectOneMenu value="#{operationBox.selected}"
valueChangeListener="#{broker.operationChanged}" onchange="submit()"
style="width:50%">
<f:selectItems value="#{operationBox.operations}" />
</p:selectOneMenu>
The broker class (Portlet 2) handles the action, sets a custom event in the ActionResponse object and the listener (Portlet 1) receives it.
BUT, I don't want to submit the form, because that would cause a page refresh, which I don't need. I'm not going to render anything in Portlet 1. My broker class looks just like the examples provided in Liferay tutorials and demo apps:
public void submit() {
logger.debug("Submitting booking changes.");
QName qName = new QName("http://liferay.com/events", "ipc.customerEdited");
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
ActionResponse actionResponse = (ActionResponse) externalContext.getResponse();
actionResponse.setEvent(qName, bookingsModelBean.getCustomer());
}
I don't know if it is ajax or the selectOneMenu
tag (or both) that fail me here: if I do the following
<f:ajax event="change" listener="#{broker.handle}"/>
the response object my broker bean gets is ResourceResponse
, which I cannot cast to ActionResponse
in order to call setEvent(QName qname, String string)
.
Is there a way for selectOneMenu
to trigger an action on value change?
Are actions only tied to submits / page reloads?
I need a way to send data to the server-side of Portlet 1 from Portlet 2. What's my best option in your opinion?
Thanks a lot
EDIT with final solution
It turns out that this cannot be done via server-side event processing with the current specs. I eventually managed to do it with client-side javascript. The following method works only if the involved portlets are on the same page: Portlet 1 - fire event:
<p:selectOneMenu value="#{operationBox.selected}"
onchange="return myFireEvent('operation',this.value);>
and
<script>
function myFireEvent(caller, value) {
var payload = ...; // process your parameters
Liferay.fire('my-event-name', {
payload: payload
});
return false;
};
</script>
Portlet 2 - receive event:
The workaround I used to send data to the server side is to call a custom js function via <p:remoteCommand>
tag, that you must place inside a <h:form>
:
<p:remoteCommand name="handleEvent" actionListener="#{icpReceiver.handleEventJS}"/>
This is invoked by the js receiver function provided by the Liferay API:
<script>
Liferay.on('my-event-name', function(event) {
handleEvent([{name:'payload', value:event.payload}]);
});
</script>
And that's all.