1
votes

I'm trying to filter a p:dataTable with Primefaces component p:selectCheckboxMenu in one column header. This however, does not work as intended. The other filters on the datatable work just fine, such as input fields. The column in question is the Room type, that has the p:selectCheckboxMenu.

The filtering works once, after that checking or unchecking boxes on the selectCheckbox menu doesn't add or remove any filtering on the table.

Here's an interesting bit on the problem:

If I remove the selectionMode="single" attribute from the datatable, then the sorting works even after the first checkBox toggle. As in, I can toggle and untoggle a box and the p:dataTable gets filtered accordingly. But, I need the selection mode here, since I'm supposed to be able to select a row and navigate to another view by clicking it. That doesn't work when there's no selectionMode attribute on the datatable.

Here's my datatable:

<div class="background">

        <div class="freeRoomsContent">

            <br/>
            <p:outputLabel value="free rooms" styleClass="headerfont"/>
            <br/>
    <h:form id="freeRoomsForm">
        <p:dataTable id="freeRoomsTable" var="room" paginatorPosition="bottom" paginatorAlwaysVisible="false"
                     value="#{freeRoomsController.freeRoomsList}" selectionMode="single" selection="#{freeRoomsController.room}"
                     rowKey="#{room.roomId}" widgetVar="freeRoomsTable"
                     paginator="true" rows="20" pageLinks="5" scrollable="false"
                     paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
                     rowsPerPageTemplate="20,50,100" skipChildren="true" emptyMessage="No free rooms available.">
            <p:ajax event="rowSelect" listener="#{freeRoomsController.onRowSelect}" />
            <p:column headerText="Room Id" sortBy="#{room.roomId}" filterMatchMode="contains" filterBy="#{room.roomId}">
                <h:outputText value="#{room.roomId}"/>
              </p:column>

            <p:column headerText="Room number" sortBy="#{room.roomNumber}" filterMatchMode="contains" filterBy="#{room.roomNumber}">
                <h:outputText value="#{room.roomNumber}" />
            </p:column>
<!-- other similar columns -->

            <p:column headerText="Room type" filterMatchMode="exact" filterBy="#{room.roomType}">
                <f:facet name="filter">
                    <p:selectCheckboxMenu  onchange="PF('freeRoomsTable').filter()"
                                     label="Room type">
                        <f:selectItems value="#{staticData.roomTypes}" var="rt" itemLabel="#{msg[rt.name]}" itemValue="#{rt.name}"
                                       />
                    <p:ajax event="change" process="@this" update="freeRoomsForm" />
                    <p:ajax event="toggleSelect" process="@this" update="freeRoomsForm" />
                    </p:selectCheckboxMenu>
                </f:facet>
                <h:outputText value="#{msg[room.roomtype.name]}">
                    <f:convertDateTime pattern="dd.MM.yyyy" />
                </h:outputText>
            </p:column>

<!-- normal input field columns that work -->

        </p:dataTable>
    </h:form>
</div>
</div>
1
have you tried to remove p:ajax nested inside p:selectCheckboxmenu? i think filter() function itself fire ajax request. also, try to add p:ajax event=filter nested in datatable (e.g. below p:ajax for rowSelect)Nikola

1 Answers

3
votes

This worked for me:

  • Using value and filteredValue in p:dataTable

  • Use only onchange=PF('freeRoomsTable').filter(), without child p:ajax elements in p:selectCheckboxMenu

  • Set value attribute for p:selectCheckboxMenu, e.g. value="#{someBean.selectedItems}"

  • In your bean, use private String[] selectedItems, with getter and setter

  • In your bean implement filterFunction, method need to have signature boolean (Object, Object, Locale) altough for this example only 1st argument (Object value) is used:
    public boolean filterFunction(Object value, Object filter, Locale locale) {
    
        // instanceof checking probably not needed
        if (value == null || !(value instanceof String)) {
            return true;  
        }
    
        String valueInRow = (String)value;
    
        // if nothing is selected, show row in table i.e. return true, 
        // you can play with this ofcourse
        if (selectedItems == null || selectedItems.length == 0) {
            return true;
        }
    
        // if item in row matches any of the items that were selected in header,    
        // show in table i.e. return true
        for (int i = 0; i < selectedItems.length; i++) {
            if (selectedItems[i].equals(valueInRow)) {
                return true;
            }
        }
    
        // if you don't want to show row in table, return false
        return false;
    
    }
    

  • In p:column, call filterfunction=#{someBean.filterFunction} - no arguments, no parenthesis, no need to use any filterMatchMode, leave only filterBy