I have a web page which is including a sub-page that changes according to the element I choose in the primefaces dock menu (ui:include
). Some sub pages include a custom composite component I implemented. The first page the web app shows has all his listeners working correctly. When I change sub-page via the dock menu, VideoStatusTable's listeners (composite component's listeners) won't work until I refresh the page in the browser (with F5) OR if I select the page again in the dock menu.
Here is the main page holding the dock menu.
<h:body style="width:100%;height:100%;position:relative;">
<h:panelGroup id="contentPanelGroup">
<ui:include src="#{Template.currentView.view}" />
</h:panelGroup>
<div id="header-wrapper">
<h:form id="headerForm" styleClass="titleSize" style="position:relative;height:100%;width:100%;">
</h:form>
</div>
<div id="footer-wrapper">
<h:form id="footerForm">
<h:graphicImage name="ctec.png" library="images" style="position:absolute;left:30px;bottom:10px;"/>
<p:dock>
<p:menuitem value="#{msgs.ViewEnum_TRANSFER}" icon="#{resource['images:hard-drive-download.png']}" action="#{Template.setWindow( 0 )}" update=":contentPanelGroup :headerForm :msgsArea" />
<p:menuitem value="#{msgs.ViewEnum_STATUS}" icon="#{resource['images:gears.png']}" action="#{Template.setWindow( 1 )}" update=":contentPanelGroup :headerForm :msgsArea"/>
<p:menuitem value="#{msgs.ViewEnum_ORGANIZATION}" icon="#{resource['images:folder.png']}" action="#{Template.setWindow( 2 )}" update=":contentPanelGroup :headerForm :msgsArea" />
<p:menuitem value="#{msgs.ViewEnum_VALIDATION}" icon="#{resource['images:chart-bar.png']}" action="#{Template.setWindow( 3 )}" update=":contentPanelGroup :headerForm :msgsArea" />
<p:menuitem value="#{msgs.ViewEnum_REPORT}" icon="#{resource['images:documents.png']}" action="#{Template.setWindow( 4 )}" update=":contentPanelGroup :headerForm :msgsArea" />
</p:dock>
</h:form>
</div>
<p:growl id="msgsArea" life="5000"/>
<ui:debug/>
</h:body>
TemplateBean
looks like this:
@Named(value="Template") // CDI
@SessionScoped // CDI
public class TemplateBean implements Serializable {
private static final long serialVersionUID = -8230221469543897876L;
private Integer window = 2;
// Some getters ...
// Get Window
public Integer getWindow() {
return window;
}
public void setWindow( Integer window ) {
this.window = window;
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage( FacesMessage.SEVERITY_INFO, getCurrentViewTitle(), getCurrentViewTitle() )
);
FacesContext.getCurrentInstance().addMessage(
null,
new FacesMessage( FacesMessage.SEVERITY_ERROR, getCurrentViewTitle(), getCurrentViewTitle() )
);
}
}
ViewEnum
(which is used for choosing which view is shown):
public enum ViewEnum {
TRANSFER ( "hard-drive-download.png", "/private/VideoTransfer.xhtml" ),
STATUS ( "gears.png", "/private/ProcessStatus.xhtml" ),
ORGANIZATION ( "folder.png", "/private/DataOrganization.xhtml" ),
VALIDATION ( "chart-bar.png", "/private/ProcessValidation.xhtml" ),
REPORT ( "documents.png", "/private/ReportGeneration.xhtml" ),
;
private String iconFileName;
private String view;
private StreamedContent icon = null;
private ViewEnum( String iconFileName, String view ) {
this.iconFileName = iconFileName;
this.view = view;
}
public String getIconFileName() {
return this.iconFileName;
}
public String getTranslationKey() {
return "ViewEnum_" + this.toString();
}
public StreamedContent getIcon() {
// irrelevant code ...
}
public String getView() {
return this.view;
}
}
The custom component:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:cmpnt="http://java.sun.com/jsf/composite/component">
<composite:interface componentType="videoStatusTableComponent">
<composite:attribute name="value" required="true"/>
<composite:attribute name="selection" required="true"/>
<composite:attribute name="selectionListener" required="true" method-signature="void listener(org.primefaces.event.SelectEvent)"/>
<composite:attribute name="selectionUpdate" required="false" default="@this"/>
<composite:attribute name="refreshListener" required="true" method-signature="void action()"/>
</composite:interface>
<composite:implementation>
<p:dataTable id="cmpntVideoList" var="video" value="#{cc.attrs.value}" rowKey="#{video.key}" style="clear:both;"
selection="#{cc.attrs.selection}" selectionMode="single" emptyMessage="#{cc.attrs.emptyValueListMsg}">
<p:ajax event="rowSelect" listener="${cc.selectionListener}" process="@this" update="${cc.attrs.selectionUpdate}"/>
<composite:insertFacet name="header"/>
<p:column headerText="Test">
#{video.humanReadableVideoId}
</p:column>
<f:facet name="footer">
<h:commandLink action="${cc.attrs.refreshListener}" style="float:right;">
<h:graphicImage library="images" name="button-rotate-cw_16.png"/>
<f:ajax render="cmpntVideoList" execute="@this"/>
</h:commandLink>
</f:facet>
</p:dataTable>
</composite:implementation>
</html>
@FacesComponent( "videoStatusTableComponent" )
public class VideoStatusTableComponent extends UINamingContainer {
public void selectionListener( org.primefaces.event.SelectEvent event ) {
FacesContext context = FacesContext.getCurrentInstance();
MethodExpression ajaxEventListener = (MethodExpression) getAttributes().get( "selectionListener" );
ajaxEventListener.invoke( context.getELContext(), new Object[] { event } );
}
}
The first sub-page (and its Bean), which includes the component:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:cmpnt="http://java.sun.com/jsf/composite/component">
<ui:composition>
<h:form id="contentForm">
<cmpnt:videoStatusTable id="transferingVideoList"
value="#{videoTransfer.tableModel}"
selection="#{videoTransfer.selectedTableReadyNotCompletelyTranferedVideo}"
selectionListener="${videoTransfer.onVideoSelection}"
selectionUpdate=":msgsArea"
refreshListener="${processStatus.refreshUncompletedVideos}"
>
</cmpnt:videoStatusTable>
</h:form>
</ui:composition>
</html>
@Named( value="videoTransfer" ) // CDI
@SessionScoped // CDI
public class VideoTransferBean implements Serializable {
private static final long serialVersionUID = -9019701853654362317L;
private VideoStatus selectedTableReadyNotCompletelyTranferedVideo;
private VideoStatusTableModel tableModel;
private List<Video> currentlyTranferingVideos = null;
// Other irrelevant code...
public VideoStatusTableModel getTableModel() {
return tableModel;
}
public void setSelectedTableReadyNotCompletelyTranferedVideo(VideoStatus selectedTableReadyNotCompletelyTranferedVideo) {
this.selectedTableReadyNotCompletelyTranferedVideo = selectedTableReadyNotCompletelyTranferedVideo;
}
public VideoStatus getSelectedTableReadyNotCompletelyTranferedVideo() {
return selectedTableReadyNotCompletelyTranferedVideo;
}
public void onVideoSelection( SelectEvent event ) {
FacesMessage msg = new FacesMessage( "Video Selected: " + ((VideoStatus) event.getObject()).getHumanReadableVideoId() );
FacesContext.getCurrentInstance().addMessage( null, msg );
}
}
Another sub-page that includes the same component (here the listeners don't work until I reload the page (via the dock or if I hit F5)):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:cmpnt="http://java.sun.com/jsf/composite/component"
>
<ui:composition>
<h:form id="contentForm">
<cmpnt:videoStatusTable
id="orphanVideoList"
value="#{DataOrganization.videoTableModel}"
selection="#{DataOrganization.selectedVideo}"
selectionListener="#{DataOrganization.onOrphanVideoSelection}"
selectionUpdate=":msgsArea"
refreshListener="#{DataOrganization.refreshOrphanVideos}"
/>
</h:form>
</ui:composition>
</html>
@Named(value="DataOrganization") // CDI
@SessionScoped // CDI
public class DataOrganizationBean implements Serializable, MonitoredBean {
private static final long serialVersionUID = 1686055743669628317L;
// Constants and variables
@EJB
private DataOrganizationEJB controller;
private Integer companyEntityID = null;
private VideoStatusTableModel videoTableModel;
private VideoStatus selectedVideo;
public void refreshOrphanVideos() {
setOrphanVideos(controller.getOrphanVideos(getCompanyEntityID()));
}
public void onOrphanVideoSelection(org.primefaces.event.SelectEvent event) {
this.setSelectedVideo(((VideoStatus) event.getObject()));
}
public VideoStatusTableModel getVideoTableModel() {
return videoTableModel;
}
public VideoStatus getSelectedVideo() {
return selectedVideo;
}
public void setSelectedVideo(VideoStatus selectedVideo) {
this.selectedVideo = selectedVideo;
}
}
Does anyone have a clue on how to avoid reloading the web page to get the component's listeners to work?
In web XML I have set the STATE_SAVING_METHOD
to client.
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
N.B.: I use JSF 2.0, Glassfish 3.1.2.2, Primefaces 3.4.
Thanks!
**** UPDATED ****
I found out the problem really comes from the components. If I use the exact same code without the use of components everything works fine.
Did anyone encountered this problem?
This looks very similar to some behaviors I have noticed and this issue found at: http://java.net/jira/browse/JAVASERVERFACES-2050
I had the same issue but you really should avoid doing this! You should do less generic components. It worked for me.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With