java - 复合组件监听器仅在页面重新加载后工作

标签 java ajax jsf composite-component

我有一个网页,其中包含一个子页面,该子页面根据我在 primefaces 停靠菜单 (ui:include) 中选择的元素而变化。一些子页面包含我实现的自定义复合组件。 Web 应用程序显示的第一页让他的所有听众都正常工作。当我通过停靠菜单更改子页面时,VideoStatusTable 的监听器(复合组件的监听器)将无法工作,直到我在浏览器中刷新页面(使用 F5)或者如果我在 jetty 菜单。

这是包含停靠栏菜单的主页。

<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 看起来像这样:

@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(用于选择显示哪个 View ):

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;
    }
}

自定义组件:

<?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 } );
    }

}

第一个子页面(及其 Bean),其中包含组件:

 <?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 );
    }
    }

另一个包含相同组件的子页面(这里的监听器只有在我重新加载页面(通过 dock 或如果我按下 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;
    }
}

有没有人知道如何避免重新加载网页以使组件的监听器工作?

在 web XML 中,我将 STATE_SAVING_METHOD 设置为客户端。

<context-param>
    <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
    <param-value>client</param-value>
</context-param>

注意: 我使用 JSF 2.0、Glassfish 3.1.2.2、Primefaces 3.4。

谢谢!

**** 已更新 ***< em>*

我发现问题确实出在组件上。如果我使用完全相同的代码而不使用组件,一切正常。

有人遇到过这个问题吗?

最佳答案

这看起来与我注意到的一些行为非常相似,这个问题发现于:http://java.net/jira/browse/JAVASERVERFACES-2050

关于java - 复合组件监听器仅在页面重新加载后工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12589037/

相关文章:

java - 避免未初始化的非最终成员类/类变量

PHP MySQL UPDATE 查询未从文本框中发布值

php - onkeypress 使用 ajax js 和 php 进行电子邮件验证

jsf - 从 Facelets 中向数据表行添加最后一行

java - Apache Http 客户端编码 UTF-8 不起作用

java - 为什么在单条记录上调用 Spring Data JPA save() 比在记录列表上调用它慢?

java - 使用java中的正则表达式验证用户输入字符串是否匹配特定模式

javascript - 未捕获的语法错误 : Unexpected token < in &lt;! DOCTYPE html>

java - 我可以将 ".jar"导入 JSF 并使用它吗?

java - 将颜色更改为 <ice :commandLink>