绑定在p:dataTable,它被多次包含会导致ID unqiueness异常

时间:2015-05-27 14:16:05

标签: jsf-2 primefaces binding datatable facelets

我正在尝试使用这个答案中使用的特殊PrimeFaces数据导出器实现:

https://stackoverflow.com/a/14413932/396732

然而,我们的用例有点复杂,例如使用Facelets显示要导出的相应数据表,其中包含行子扩展,其中包含子表。

insiderListManagerDialogs.xhtml:

<ui:include src="insiderListManagerListDialog.xhtml">
    <ui:param name="idPrefix" value="il-emp" />
    <ui:param name="widgetVarPrefix" value="ilEmp" />
    <ui:param name="dialogTitle" value="#{msg['entity.employee.internal.plural.label']}" />
    <ui:param name="mapPropertyName" value="insiderListEmployeesMap" />
    <ui:param name="sortColumn" value="#{ent.lastTime}" />
    <ui:param name="keyColumnsXhtml" value="listDialogInsiderListKeyColumns.xhtml" />
    <ui:param name="valueColumnsXhtml" value="listDialogEmployeeValueColumns.xhtml" />
</ui:include>

insiderListManagerListDialog.xhtml:

<p:dialog id="#{idPrefix}-il-view-dialog"
          widgetVar="#{widgetVarPrefix}Dialog"
          header="#{dialogTitle}"
          modal="true"
          resizable="false"
          appendToBody="true" 
          onShow="resetFilterInput( '#{idPrefix}' );"
          width="1000"
          height="750">

    <h:form id="#{idPrefix}-il-view-form">
        <p:dataTable id="list-entities"
                     widgetVar="listEntitiesTable"
                     binding="#{table}"
                     value="#{insiderListManager.listInstances}"
                     var="key"
                     scrollable="true"
                     scrollHeight="625"
                     scrollWidth="985"
                     resizableColumns="true"
                     expandedRow="#{insiderListManager.listEntitiesRowTogglerOpen}"
                     filteredValue="#{insiderListManager.filteredEntities}"
                     sortBy="#{sortColumn}"
                     styleClass="bx-datatable-header-hidden-m"
                 tyle="width: 970px;">

            <f:facet name="header">
                <p:inputText id="globalFilter"
                             onkeypress="if (event.keyCode == 13) { listEntitiesTable.filter(); return false;}"
                             size="70"
                             styleClass="bx-dt-header-element" />
                <p:commandButton id="search-btn"
                                 icon="ui-icon bx-icon-search"
                                 value="#{msg['common.action.search.label']}"
                                 process="@this"
                                 onclick="listEntitiesTable.filter(); return false;"
                                 styleClass="bx-dt-header-element" />            
                <p:commandButton title="#{msg['common.action.excelExport.all.hint']}"
                                 icon="ui-icon bx-icon-excel"
                                 action="#{insiderListManager.exportXls( table )}"
                                 ajax="false"
                                 styleClass="bx-button-border bx-dt-header-element" />
                 <div class="bx-clear-float" />
            </f:facet>

            <p:column width="15"
                      resizable="false">

            ...

            <p:rowExpansion> 
                <p:dataTable value="#{insiderListManager[mapPropertyName].get(key)}"
                             var="value">

                    <ui:include src="#{valueColumnsXhtml}" />

                </p:dataTable>
            </p:rowExpansion> 
        </p:dataTable>

        <h:panelGroup id="button-panel" layout="block" styleClass="left-button-panel mt-5px">
            <p:commandButton id="toggle-button"
                             icon="#{insiderListManager.listEntitiesRowTogglerOpen ? 'ui-icon ui-icon-circle-triangle-e' : 'ui-icon ui-icon-circle-triangle-s'}"
                             value="#{insiderListManager.listEntitiesRowTogglerOpen ? msg['common.action.collapseAll.label'] : msg['common.action.expandAll.label']}"
                             process="@this"
                             update="@form">
                <f:setPropertyActionListener target="#{insiderListManager.listEntitiesRowTogglerOpen}"
                                             value="#{not insiderListManager.listEntitiesRowTogglerOpen}" />
            </p:commandButton>
        </h:panelGroup>

    </h:form>
</p:dialog>

注意

<p:commandButton title="..."
                 icon="ui-icon bx-icon-excel"
                 action="#{insiderListManager.exportXls( table )}"
                 ... />

使用绑定数据表,如顶部发布的链接所述。

我们正在使用 JSF 2.1 (Mojarra 2.1.22 - 我们无法切换到MyFaces),它允许表达式从#{idPrefix}-il-view-dialog构建<ui:param name="idPrefix" value="il-emp" />之类的ID。

但是,我们正在获得ID唯一性异常:

Caused by: java.lang.IllegalStateException: Component ID il-emp-il-view-form:list-entities:globalFilter has already been found in the view.  
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:846)
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:830)
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:830)
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:830)
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:830)
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:830)
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:830)
    at com.sun.faces.util.Util.checkIdUniqueness(Util.java:830)
    at com.sun.faces.application.view.StateManagementStrategyImpl.saveView(StateManagementStrategyImpl.java:144)
    at com.sun.faces.application.StateManagerImpl.saveView(StateManagerImpl.java:133)
    at com.sun.faces.application.view.WriteBehindStateWriter.flushToWriter(WriteBehindStateWriter.java:225)
    at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:419)
    at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:131)
    at com.ocpsoft.pretty.faces.application.PrettyViewHandler.renderView(PrettyViewHandler.java:163)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
    at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:288)
    at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:121)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
    ... 49 more

如果省略了具有显式ID的其他按钮也会发生相同的情况,例如搜索按钮(<p:commandButton id="search-btn" ...)。

问题

为什么会发生这种情况?当我们必须为显示的每个用例使用PrimeFaces对话框时,我们如何避免这个问题? (我们有多个对话框)

请注意,删除<p:dataTable ... binding="..."页面时,该工作正常。

1 个答案:

答案 0 :(得分:2)

您基本上将物理上不同的<p:dataTable>组件绑定到同一个EL变量。如果此EL变量不为null(即已由同一视图中的先前组件设置),则JSF将重用而不是创建新的变量,并在视图构建期间覆盖其所有属性,在视图渲染时间内导致“怪异”行为,并在状态保存期间可能出现重复的组件ID错误。

在特定情况下,您可以使用UIComponent#getNamingContainer()直接引用子组件内的父<p:dataTable>组件。

<p:dataTable ... (NO binding!)>
    ...
    <p:comandButton ... action="#{bean.exportXls(component.namingContainer)}" />

它可能会嵌套在另一个 NamingContainer组件中,然后您需要使用#{component.namingContainer.parent.namingContainer}。等等多个。