Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Composite component listeners only working after page reload

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?

like image 550
fostiguy Avatar asked Nov 04 '22 15:11

fostiguy


2 Answers

This looks very similar to some behaviors I have noticed and this issue found at: http://java.net/jira/browse/JAVASERVERFACES-2050

like image 96
ChaudPain Avatar answered Nov 13 '22 08:11

ChaudPain


I had the same issue but you really should avoid doing this! You should do less generic components. It worked for me.

like image 41
user2646944 Avatar answered Nov 13 '22 07:11

user2646944