5

I have a PrimeFaces tree table and would like to add a check box which allows the user to select/unselect all.

Here is an extract from my xhtml

<p:selectBooleanCheckbox
        itemLabel="Select all"                                      
        value="#{mainViewBean.selectAll}">
        <p:ajax listener="#{mainViewBean.onSelectAll}"
            update="@this :mainForm" />
    </p:selectBooleanCheckbox>  

    <p:treeTable id="treeToAssign"
        value="#{mainViewBean.treeValue}" var="vh"
        selectionMode="checkbox"
        selection="#{mainViewBean.treeSelection}">
        <f:facet name="header">
            Tree Table                                                  
        </f:facet>                                                              
        <p:column>                                      
            <h:outputText value="#{vh.name}" />
        </p:column>                                 
    </p:treeTable>

and here is my bean method

private TreeNode treeValue;
private TreeNode[] treeSelection;
private boolean selectAll;

public void onSelectAll() {             
    List<TreeNode> selection = new ArrayList<>();
    for (TreeNode node : treeValue.getChildren()) {
    node.setSelected(selectAll);
        selection.add(node);
    }

    treeSelection = selection.toArray(new TreeNode[selection.size()]);
}

I had initially tried just setting NODE.setSelected(selectAll);, but that didn't work so I tried manually manually filling treeSelection as well.

I feel like this should be straightforward, but have been unable to figure it out, any suggestions?

Thanks

hello123
  • 951
  • 2
  • 15
  • 25

2 Answers2

2
  • Make your bean at least @ViewScoped
  • Create additional field private Set<TreeNode> selectedNodesSet = new HashSet<>();
  • Use recursion for selecting/deselecting
public void onSelectAll() {
    for (TreeNode node : treeValue.getChildren()) {
        recursiveSelect(node);
    }

    treeSelection = new TreeNode[selectedNodesSet.size()];
    Iterator<TreeNode> iterator = selectedNodesSet.iterator();
    int index = 0;

    while (iterator.hasNext()) {
        treeSelection[index++] = iterator.next();
        iterator.remove();
    }
}

private void recursiveSelect(TreeNode node) {
    node.setSelected(selectAll);

    if (selectAll) {
        selectedNodesSet.add(node);
    } else {
        selectedNodesSet.remove(node);
    }

    for (TreeNode n : node.getChildren()) {
        recursiveSelect(n);
    }
}
Jens Piegsa
  • 7,399
  • 5
  • 58
  • 106
Geinmachi
  • 1,251
  • 1
  • 8
  • 20
  • This has worked to an extent. With logging/debugging I can see that the nodes are all being selected, but the checkboxes aren't being visibly ticked on screen. Any suggestions for this? – hello123 Nov 19 '15 at 08:12
  • The line `node.setSelected(selectAll);` should check them. You can iterate over nodes and check if they are selected after execution of `recursiveSelect` for loop. Also try adding `@form` or even `@all` to `update="@this :mainForm"` and see if maybe there lies the problem. – Geinmachi Nov 19 '15 at 17:42
1

Basically PrimeFaces uses the term node in the treeTable to refer to each row, and it provides a javascript function PrimeFaces.widget.TreeTable.selectNodesInRange(node) for selecting all the nodes in a rage of another node, and also another function to unselect all the nodes PrimeFaces.widget.TreeTable.unselectAllNodes().

Thus, having the following function (for selecting all, no need to have one for unselecting, it's already present):

function selectAllInTreeTable(widgetVar) {
   widgetVar.tbody.find('tr').each(function() {
      widgetVar.selectNodesInRange($(this));
   });
}

and assuming your widgetVar for the treeTable is treeTableWV, and adjusting the selectAll booleanCheckbox into this:

<p:selectBooleanCheckbox widgetVar="selectAllCheckBox" onchange="PF('selectAllCheckBox').isChecked()?PF('treeTableWV').unselectAllNodes():selectAllInTreeTable(PF('treeTableWV'))" >
   ...
</p:selectBooleanCheckbox>

Would do it.

Hatem Alimam
  • 9,968
  • 4
  • 44
  • 56