Search code examples
primefacesjsf-2

Primefaces datatable with column toggler conflicts with sort function on column


I have a data table that has a column toggler. When I uncheck a column and sort on a field the table is wrong. The header of the unchecked field pops back up and all data shift to the left, which leaves 1 column empty.

My table.xhtml file:

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

Solution

  • I found my answer in this blog post: http://blog.primefaces.org/?p=3341

    The solution was to keep the Visibility state of all columns in the backing bean.

    The toggler must trigger the onToggle function in your backing bean:

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

    Each column must be set by the boolean list in the backing 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>
    

    In the backing bean you must have a list of booleans which represents the visibility of each field:

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

    In the @PostConstruct method you must initialize this list of beans:

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