【问题标题】:JSF 2 with richfaces 4.3 - Duplicate id when AJAX request and rendering带有richfaces 4.3的JSF 2 - AJAX请求和呈现时重复的ID
【发布时间】:2017-01-27 23:40:18
【问题描述】:

有一个数据表,其中每个列标题都有排序和过滤图标,分别对数据进行排序和过滤。 两者都工作正常。这里,“columnHeader”是一个不同的文件,其中实现了 Composite。 如果我单击过滤器图标,则会弹出相应的rich:popupPanel(包含关键字的 inputText 和用于操作的按钮),如果我单击另一个, 前一个被隐藏(显示:无),其他被弹出。 "rich:popupPanel" 保持未关闭状态,除非手动关闭或单击另一个过滤器图标。

问题: 点击过滤器图标后,会弹出rich:popupPanel。如果我让它打开并执行排序,一切正常,但是,另一个重复的 popupPanel 已经在 DOM 中创建。两者的id是一样的。每次我排序时,每次新的 popupPanel 一次又一次地重复。所以对应的过滤器图标会渲染不止一个popupPanel。我认为这是由于 AJAX 请求或渲染问题?

例如:

<html ...
    xmlns:cpd="http://java.sun.com/jsf/composite/cpd">

<rich:dataTable value="#{bean.tableData}" var="data" id="myTable">
    <rich:column>
        <f:facet name="header">
            <cpd:columnHeader backingbean="${bean}" columnid="empid" />
        </f:facet>
        <h:ouputText value="#{data.eid}" />
    </rich:column>
    <rich:column>
        <f:facet name="header">
            <cpd:columnHeader backingbean="${bean}" columnid="empname" />
        </f:facet>
        <h:ouputText value="#{data.ename}" />
    </rich:column>
    ...
</rich:dataTable>

columnHeader.xhtml

<html ...>
    <composite:interface>  
        <composite:attribute name="backingbean" />
        <composite:attribute name="columnid" />
        </composite:interface>
    <composite:implementation> 
        <c:set var="backingbean" value="#{cc.attrs.backingbean}" /> 
        <c:set var="columnid" value="#{cc.attrs.columnid}" />   
        <c:set var="columnFilterLink" value="#{columnid}_filterLink" /> 
        <c:set var="columnFilterPopupId" value="#{cc.attrs.columnid}_columnFilterPopup" />  

        <table id="columnHeader">
            <tr>
                <td>                    
                     <h:outputLabel value="#{backingbean.columns[columnid].label}" escape="false" />
                </td>
                <td>    
                    <!-- Sort -->
                    <a4j:commandLink id="column_#{columnid}_sortCommandLink" actionListener="#{backingbean.doSort}" 
                        rendered="${backingbean.columns[columnid].sortable}" render="myTable">
                        <i class="fa fa-sort"/>     
                        <a4j:param name="orderField" value="#{backingbean.columns[columnid].name}" />
                        <a4j:param name="order" value="#{backingbean.columns[columnid].nextSortOrder}" />
                    </a4j:commandLink>

                    <!-- Filter -->
                    <h:outputLink value="#" id="#{columnFilterLink}" rendered="#{empty backingbean.columns[columnid].filter}" onclick="closeAllOtherFilters('#{rich:clientId(columnFilterPopupId)}')" disabled="#{(backingbean.recordCount le 0)">
                        <rich:componentControl event="click" operation="show" target="#{columnFilterPopupId}">
                            <a4j:param name="event" value="event" noEscape="true" />
                            <rich:hashParam>
                                <a4j:param noEscape="true" name="top"
                                    value="jQuery(#{rich:element(columnFilterLink)}.parentNode).offset().top + jQuery(#{rich:element(columnFilterLink)}.parentNode).height()" />
                                <a4j:param noEscape="true" name="left" value="jQuery(#{rich:element(columnFilterLink)}.parentNode).offset().left" />
                            </rich:hashParam>
                        </rich:componentControl>
                        <i class="fa fa-filter"/>
                    </h:outputLink>

                    <!-- Popup panel -->
                    <rich:popupPanel id="#{columnFilterPopupId}" >
                        <table cellspacing="0">
                            <tr><td>                
                                    <h:outputLabel value="#{backingbean.columns[columnid].label}" escape="false" />
                                </td>
                                <td align="right">
                                    <h:outputLink value="#" onclick="closeFilters('#{rich:clientId(columnFilterPopupId)}');#{rich:component(columnFilterPopupId)}.hide(); return false;">
                                    X </h:outputLink>
                                </td>                               
                            </tr>

                            <tr><td colspan="2"><div class="d2-separator" /></td></tr>
                            <tr><td colspan="2">                
                                <h:inputText styleClass="columnFilterInputText" id="#{columnFilterInputText}"  style="width:98%" value="#{backingbean.columns[columnid].filter}"/> 
                                <!-- <rich:inplaceInput id="#{columnFilterInputText}" defaultLabel="enter filter string" style="width:159px" value="#{backingbean.columns[columnid].filter}"/> -->
                                </td>
                            </tr>
                            <tr><td  colspan="2">

                                <a4j:commandButton id="#{columnid}_filterButton" actionListener="#{backingbean.doFilter}"
                                                 value="Apply Filter"   onclick="if(validateFilter('#{rich:clientId(columnFilterInputText)}','#{backingbean.columns[columnid].filterType}')){#{rich:component(columnFilterPopupId)}.hide(event); return true;} else return false;"
                                                 render="myTable">  
                                </a4j:commandButton>                 
                                <a4j:commandButton id="#{columnid}_resetButton" actionListener="#{backingbean.doFilter}"
                                                  value="Reset Filter"  onclick="resetFilterForTable('#{rich:clientId(columnFilterInputText)}');#{rich:component(columnFilterPopupId)}.hide(event); return true;"
                                                  render="myTable">
                                </a4j:commandButton>                                             

                                </td></tr><tr><td colspan="2"></td></tr>
                       </table>         
                </rich:popupPanel>
            </composite:implementation>
        </html>

豆码:

...
public void doSort(ActionEvent evt) {
        super.doSort(evt);
        loadTable();
    }
...

BaseController : (Bean 扩展 BaseController)

public void doSort(ActionEvent evt) {
        dataSetParameters.setPageNo(1);
        String orderField = (String) resolveFromRequestParameterMap("orderField");
        if (!orderField.equalsIgnoreCase(getOrderField())
                && getOrderField() != null
                && getColumns().get(getOrderField()) != null)
            getColumns().get(getOrderField()).setSortOrder("");

        setOrderField((String) resolveFromRequestParameterMap("orderField"));
        setOrder((String) resolveFromRequestParameterMap("order"));
        getColumns().get(getOrderField()).setSortOrder(getOrder());
    }

Javascript:

function closeAllOtherFilters(filterid){ 
    var nodes = document.querySelectorAll('.columnFilterPopup')
    for (var i=0; i<nodes.length; i++){     
        var outerNodeId = nodes[i].id.replace(/_container/i, '');
        var outerNodeElement = document.getElementById(outerNodeId);
        if(outerNodeId != filterid){
            if (outerNodeElement.style.display=="block"){
                outerNodeElement.style.display="none";   
            }
            if (nodes[i].style.display=="block"){
                nodes[i].style.display="none";   
            }
        }else{
            nodes[i].style.display="block";
            outerNodeElement.style.display="block";
        }               
    }
}

【问题讨论】:

    标签: javascript jsf richfaces render ajax4jsf


    【解决方案1】:

    这是一个错误,当弹出窗口被重新渲染时,它不会自行销毁(因为它通常位于 DOM 中的父级之外)。要绕过它,请在触发请求或将其放在表格之外之前关闭弹出窗口,但我认为这不是一个选项。

    顺便说一句,为什么不在数据表中使用自定义排序/过滤?其次,为什么不使用 JS API 隐藏弹出窗口,而不是手动设置显示样式?

    【讨论】:

    • 我想在请求之前关闭弹出窗口,但由于有更多的 ajax 请求会导致同样的问题,所以不可能。 “表外”当然不是一个选项:/实际上,它是一个自定义排序/过滤。对于这个问题,你能举一个 JS API 的例子吗?但是,如果 node[i] 的计数大于 1(在 javascript 代码中),我通过删除 node[i] 解决了这个问题。但这不是解决方案,而是充当黑客。感谢@Makhiel 的回复。
    • 然后在页面上的任何请求之前关闭它?您可以尝试domElementAttachment="parent",它可以将面板保持在原位,但可能会弄乱布局。至于你已经在使用的 JS API - #{rich:component(columnFilterPopupId)}.hide(event).
    • 嘿@Mahiel 非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2014-08-11
    • 2016-01-13
    • 2011-03-21
    • 2012-04-25
    • 2017-12-15
    • 2017-05-17
    • 2017-04-24
    • 1970-01-01
    相关资源
    最近更新 更多