2

I am trying to implement a "select all checkboxes" checkbox in a rich:dataTable header without using JavaScript.

XHTML:

<rich:column styleClass="center-aligned-text">
    <f:facet name="header">
        <h:selectBooleanCheckbox id="selectAll" title="selectAll" valueChangeListener="#{workspace.selectAllComponents}">
            <a4j:support event="onclick" reRender="listcomponents"/>
        </h:selectBooleanCheckbox>
    </f:facet>

    <h:selectBooleanCheckbox id="selectComponent" value="#{workspace.selectedComponentIds[componentInfo.id]}" />
</rich:column>

Backing bean:

public void selectAllComponents(ValueChangeEvent event) {
    if (!selectAll) {
        changeMap(selectedComponentIds,true);
        setSelectAll(true);
    } else { 
        changeMap(selectedComponentIds,false);
        setSelectAll(false);
    }
}


public void changeMap(Map<Long,Boolean> selectedComponentMap, Boolean blnValue) {
    if(selectedComponentMap != null) {
        Iterator<Long> itr = selectedComponentMap.keySet().iterator();
        while(itr.hasNext()) {
            selectedComponentMap.put(itr.next(), blnValue);
        }
        setSelectedComponentIds(selectedComponentMap);
    }
}

An answer which I found here:

if (event.getPhase() != PhaseId.INVOKE_APPLICATION) {
    event.setPhase(PhaseId.INVOKE_APPLICATON);
    event.queue();
} else {
   //do your stuff here
}

doesn't add up, because the getPhase() is not available in the ValueChangeEvent event. I see the just the getPhaseId() which contains the INVOKE_APPLICATION option, so my question is, how can I achieve my functional requirement with the above answer? Or is there any alternative?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555

2 Answers2

3

The valueChangeListener performs its job during the Process Validations phase. However, as the entire form is submitted, the submitted values will override the in the valueChangeListener changed values during the Update Model Values phase. You indeed want to perform the "Select all" job during the Invoke Action phase.

Better is to just let JSF skip all remaining phases in the valueChangeListener method until the render response, so that the changed values won't be overridden. You can achieve this by calling FacesContext#renderResponse() in the valueChangeListener method.

public void selectAllComponents(ValueChangeEvent event) {
    selectAll = !selectAll;
    changeMap(selectedComponentIds, selectAll);
    FacesContext.getCurrentInstance().renderResponse();
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
0

I have implemented this with a checkbox in the header facet of a datatable but with a simple jquery which selects all checkboxes in this tables rows.

If you want to avoid js and you can life without refreshing the table selection but just use the select all checkbox per se. You can just map it to a bean and treat this in your application with an a4j action(listener) where you will update your selected ids and rerender your table.

There is something more that could probably simplify your selection handler: i've created a generic selectablewrapper for the entityquery which holds a boolean and the entity of the results from the entityquery. You wrap the getresultslist with another function returning a list of these wrappers and you have something very generic. In eclipse even autocompletion of the generic is giving you the correct object.

Martin Frey
  • 10,025
  • 4
  • 25
  • 30