2016-09-20 8 views
0

Существует таблица данных, в которой каждый заголовок столбца имеет значки Сортировка и Фильтр, которые выполняют сортировку и фильтрацию данных соответственно. Оба работают нормально. Здесь «columnHeader» - это другой файл, в котором реализован Composite. Если щелкнуть по иконке «Фильтр», соответствующие богатые: popupPanel появляется (состоит из inputText для ключевого слова и кнопок для действий), и если я нажимаю другой, предыдущий скрывается (display: none), а другой всплывает. «rich: popupPanel» остается незакрытым до тех пор, пока он не будет закрыт вручную или не будет нажата другая иконка фильтра.JSF 2 с богатыми интерфейсами 4.3 - Дублирующий идентификатор, когда запрос и рендеринг AJAX

Задача: После нажатия на значок фильтра появляются всплывающие всплывающие окна rich: popupPanel. Если я оставлю его открытым и выполним Сортировку, все будет хорошо работать, но в DOM уже создан другой дубликат popupPanel. Иды обоих одинаковы. И каждый раз, когда я сортирую, каждый раз, когда новая 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> 

Bean Код:

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

ответ

0

Это ошибка, когда всплывающее окно становится rerendered не уничтожает себя (потому что это, как правило, размещены за пределами своего родителя в DOM). Чтобы обойти это, закройте всплывающее окно, прежде чем запускать запрос или разместить его за пределами таблицы, но я предполагаю, что это не вариант.

Кстати, почему бы не использовать пользовательскую сортировку/фильтрацию в datatable? А во-вторых, почему бы не скрывать всплывающие окна с помощью JS API вместо ручной настройки стилей отображения?

+0

Я думал о закрытии всплывающего окна перед запросом, но не был возможен, так как есть больше запросов ajax, которые вызывают такую ​​же проблему. «вне таблицы», конечно, не вариант:/Собственно, это обычная сортировка/фильтрация. И можете ли вы привести пример JS API для этой проблемы? Однако я решил проблему, удалив узел [i], если его счетчик больше 1 (в коде javascript). Но это не решение, а действие. Спасибо за ответ @Makhiel. –

+0

Затем закройте его перед любым запросом на странице? Вы можете попробовать 'domElementAttachment =" parent "', который удерживает панель на месте, но может испортиться с макетом. Что касается JS API, вы уже используете его - '# {rich: component (columnFilterPopupId)}. Hide (event)'. – Makhiel

+0

Hey @Mahiel Спасибо большое! –