【问题标题】:Primefaces datatable with column toggler conflicts with sort function on column具有列切换器的 Primefaces 数据表与列上的排序功能冲突
【发布时间】:2016-09-27 06:45:52
【问题描述】:

我有一个带有列切换器的数据表。当我取消选中一列并对字段进行排序时,该表是错误的。未选中字段的标题重新弹出,所有数据都向左移动,其中 1 列为空。

我的 table.xhtml 文件:

<h:form>    
    <p:dataTable id="registrations" var="registration" tableStyle="table-layout: auto;" widgetVar="registrationsTable" 
        value="#{overviewBean.listOfRegistrations}" 
        filteredValue="#{overviewBean.filteredListOfRegistrations}" emptyMessage="No registrations found with given criteria" >
        <f:facet name="header">
            <p:outputPanel style="text-align:left;">
                <h:outputText value="Search all fields: " />
                <p:inputText id="globalFilter" onkeyup="PF('registrationsTable').filter()" style="width:150px;" placeholder="Enter keyword"/>

                <p:commandButton id="toggler" type="button" value="Columns"  icon="ui-icon-calculator" style="float:right;"/>
                <p:columnToggler datasource="registrations" trigger="toggler" >
                </p:columnToggler>
            </p:outputPanel> 
        </f:facet>


        <p:column headerText="Active" visible="false">
            <h:outputText value="Y" />
        </p:column>

        <p:column headerText="Firstname" filterBy="#{registration.firstname}" filterStyle="display:none" sortBy="#{registration.firstname}">
            <h:outputText value="#{registration.firstname}" />
        </p:column>

        <p:column headerText="Lastname" filterBy="#{registration.lastname}" filterStyle="display:none" sortBy="#{registration.lastname}">
            <h:outputText value="#{registration.lastname}" />
        </p:column>

    </p:dataTable>
</h:form>

【问题讨论】:

    标签: primefaces jsf-2


    【解决方案1】:

    我在这篇博文中找到了答案: http://blog.primefaces.org/?p=3341

    解决方案是保持支持 bean 中所有列的 Visibility 状态。

    切换器必须触发支持 bean 中的 onToggle 函数:

    <p:columnToggler datasource="registrations" trigger="toggler" >
        <p:ajax event="toggle" listener="#{overviewBean.onToggle}" />
    </p:columnToggler>
    

    每一列都必须由支持 bean 中的布尔列表设置:

    <p:column headerText="Entry date" sortBy="#{registration.entryDate}" visible="#{overviewBean.list[0]}">
        <h:outputText value="#{registration.entryDate}">
            <f:convertDateTime pattern="dd/MM/yyyy" />
        </h:outputText>
    </p:column>
    

    在支持 bean 中,您必须有一个布尔值列表,代表每个字段的可见性:

    private List<Boolean> list;
    
    public List<Boolean> getList() {
        return list;
    }
    
    public void setList(List<Boolean> list) {
        this.list = list;
    }
    
    public void onToggle(ToggleEvent e) {
        list.set((Integer) e.getData(), e.getVisibility() == Visibility.VISIBLE);
    }
    

    @PostConstruct 方法中,您必须初始化这个bean 列表:

    list = Arrays.asList(false, true, true);
    

    【讨论】:

      【解决方案2】:

      替代解决方案:通过继承 PrimeFaces p:columnToggler 创建您自己的有状态切换器。

      更新:弥补了列可能将其rendered 属性设置为false 的事实。

      package my.domain;
      
      import org.omnifaces.util.Components;
      import org.primefaces.behavior.ajax.AjaxBehavior;
      import org.primefaces.behavior.ajax.AjaxBehaviorListenerImpl;
      import org.primefaces.component.column.Column;
      import org.primefaces.component.columntoggler.ColumnToggler;
      import org.primefaces.component.datatable.DataTable;
      import org.primefaces.event.ToggleEvent;
      import javax.el.MethodExpression;
      import javax.faces.component.FacesComponent;
      import javax.faces.context.FacesContext;
      import javax.faces.event.AbortProcessingException;
      import javax.faces.event.ComponentSystemEvent;
      import javax.faces.event.ListenerFor;
      import javax.faces.event.PostAddToViewEvent;
      import java.io.IOException;
      
      @FacesComponent(
          value = StatefulColumnToggler.COMPONENT_TYPE,
          createTag = true,
          tagName = StatefulColumnToggler.TAG_NAME,
          namespace = StatefulColumnToggler.NAMESPACE
      )
      @ListenerFor(systemEventClass=PostAddToViewEvent.class)
      public class StatefulColumnToggler extends ColumnToggler {
          public static final String TAG_NAME = "statefulColumnToggler";
          public static final String COMPONENT_TYPE = "my.domain.statefulColumnToggler";
          public static final String NAMESPACE = "http://xmlns.domain.my/jsf/component";
      
          public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
              super.processEvent(event);
              if (event instanceof PostAddToViewEvent) {
                  // This behaviour is static, so it does not have to be in the partial state: recreate it on every request.
                  AjaxBehavior ajaxBehavior = (AjaxBehavior) getFacesContext().getApplication().createBehavior(AjaxBehavior.BEHAVIOR_ID);
                  MethodExpression methodExpression = Components.createMethodExpression("#{component.onToggleHandler}", null, new Class<?>[]{ToggleEvent.class});
                  ajaxBehavior.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl(methodExpression, methodExpression));
                  addClientBehavior("toggle", ajaxBehavior);
              }
          }
      
          public void onToggleHandler(ToggleEvent toggleEvent) {
              final DataTable dataTable = (DataTable) this.getDataSourceComponent();
              final int clientColumnIndex = (Integer) toggleEvent.getData();
              // Compensate for columns that are on the server, but not in the client.
              int columnsNotInClient = 0;
              for (int serverColumnIndex = 0; ; serverColumnIndex++) {
                  if (serverColumnIndex >= dataTable.getColumns().size()) {
                      throw new IllegalArgumentException("received index " + clientColumnIndex + " from client, but there is no rendered server side column with that index");
                  }
                  Column column = (Column) dataTable.getColumns().get(serverColumnIndex);
                  if (!column.isRendered()) {
                      columnsNotInClient++;
                  }
                  if (serverColumnIndex - columnsNotInClient == clientColumnIndex) {
                       column.setVisible(!column.isVisible());
                      // Must delete any 'user' specified value expression, or it will take precedence over the toggled value.
                       column.setValueExpression(Column.PropertyKeys.visible.name(), null);
                      break;
                  }
              }
          }
      }
      

      声明命名空间

      xmlns:my=http://xmlns.domain.my/jsf/component
      

      并将其添加到页面中。

      <my:statefulColumnToggler datasource="table_id" trigger="button_id" />
      

      【讨论】:

      • 我想知道如何调整此解决方案以使用动态列 ()
      【解决方案3】:

      在 Primefaces 6.1.10 中,您可以在 dataTable 上使用 multiViewState="true",同时在 columnToggler 中使用 ajax 调用,您可以在不使用支持 bean 解决方法的情况下保存列可见性。在我的测试中,与列上的排序功能不再冲突。

      更新:在使用 multiViewState="true" 进行更多测试后,在打开或关闭列后排序结果时似乎仍然存在一些错误。切换到另一个页面并返回会导致正确呈现的表和列顺序。创建问题https://github.com/primefaces/primefaces/issues/3088

      增强功能在以下方面实现: https://github.com/primefaces/primefaces/issues/3044

      用法是:

      <h:form id="form">
          <p:dataTable id="cars" var="car" value="#{dtBasicView.cars}" multiViewState="true">
              <f:facet name="header">
                  List of Cars
                  <p:commandButton id="toggler" type="button" value="Columns" style="float:right" icon="ui-icon-calculator" />
                  <p:columnToggler datasource="cars" trigger="toggler">
                      <p:ajax event="toggle" />
                  </p:columnToggler>
              </f:facet>
      
              <p:column headerText="Id" sortBy="#{car.id}"><h:outputText value="#{car.id}" /></p:column>
              <p:column headerText="Year" sortBy="#{car.year}"><h:outputText value="#{car.year}" /></p:column>
              <p:column headerText="Brand" sortBy="#{car.brand}" ><h:outputText value="#{car.brand}" /></p:column>
          </p:dataTable>
      </h:form>
      

      有关 PrimeFaces 中的 multiViewState 的更多信息,请参阅 TableState 演示: https://www.primefaces.org/showcase/ui/data/datatable/tableState.xhtml

      这也包括存储排序的可能性。

      新的列重新排序功能: https://github.com/primefaces/primefaces/issues/3041

      新的列调整大小功能: https://github.com/primefaces/primefaces/issues/3046

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-22
        • 2011-10-02
        • 2011-10-23
        • 2013-02-18
        • 2015-04-04
        相关资源
        最近更新 更多