CapnHook
CapnHook

Reputation: 41

PrimeFaces TreeTable - Stop Checkbox selection propagation

Environment:
PrimeFaces 6.1
JSF 2.2
Tomcat 7.0.23
Java 1.7.0_79

Implemented a TreeTable with checkbox selection, and need to prevent selection propagation up and down for parent and child nodes respectively for client and server side processing.

Example Tree:
Parent Node
--Child Node 1
----Child Sub-Node 1.1
--Child Node 2
----Child Sub-Node 2.1

Desired Behavior:
When selecting a node, only that node's checkbox should be selected.

Actual Behaviour (out of the box):
Selecting a node, child and parent nodes are selected. For example, selecting Child Node 2 in above Example Tree the Parent Node and Child Sub-Node 2.1 are also selected.

TreeTable component:

<p:treeTable id="treeTable" value="#{Bean.rootNode}" var="item" selectionMode="checkbox" nodeVar="node"
    styleClass="widthFull" showUnselectableCheckbox="true" selection="#{Bean.selectedNodes}" stickyHeader="true">
    <p:ajax event="select" listener="#{Bean.processSelect(item)}" ignoreAutoUpdate="true"/>
    <p:ajax event="unselect" listener="#{Bean.processUnselect(item)}" ignoreAutoUpdate="true"/>
    ....
</p:treeTable>

Overriding PrimeFaces JS functions:
Able to prevent propagation in client side processing by overriding PrimeFaces.widget.TreeTable.prototype.propagateUp and PrimeFaces.widget.TreeTable.prototype.getDescendants javascript functions.

PrimeFaces.widget.TreeTable.prototype.propagateUp = function(node) {
    //do nothing, overriding the TreeTable propagate selection up functionality

}

PrimeFaces.widget.TreeTable.prototype.getDescendants = function(node) {
    //do nothing other than return empty array, overriding the TreeTable propagate selection down functionality by overriding getDescendants...hopefully this doesn't cause other issues
    f = [];
    return f;
}

TreeTable Update:
The TreeTable update is performed as part of the ajax select and unselect event processing.

RequestContext.getCurrentInstance().update("inventoryForm:treeTable");

Question:
When the ajax select and unselect events are fired in order to disable selectability on specific nodes and updating the TreeTable, child node(s) are getting selected. The child nodes are not in the selectedNodes array on the Bean when processing the ajax event listeners. How can I prevent the child node(s) from being selected upon TreeTable component update?

Upvotes: 1

Views: 2242

Answers (1)

CapnHook
CapnHook

Reputation: 41

Preventing checkbox selection propagation from the server side can be accomplished by extending the CheckboxTreeNode class and overriding the propagateSelectionDown(boolean) and propagateSelectionUp() methods. Of course, you then need to build you tree content using the new class rather than CheckboxTreeNode.

public class MyCheckboxTreeNode extends CheckboxTreeNode {

    public MyCheckboxTreeNode() {
        super();
    }

    public MyCheckboxTreeNode(Object data, TreeNode parent) {
        super(data, parent);
    }

    public MyCheckboxTreeNode(Object data) {
        super(data);
    }

    public MyCheckboxTreeNode(String type, Object data, TreeNode parent) {
        super(type, data, parent);
    }

    @Override
    protected void propagateSelectionDown(boolean value) {
        //Do nothing, overriding CheckboxTreeNode method to prevent propagation down of tree node selections when ajax update is performed.
    }

    @Override
    protected void propagateSelectionUp() {
        //Do nothing, overriding CheckboxTreeNode method to prevent propagation up of tree node selections when ajax update is performed.
    }
}

Overriding an additional PrimeFaces javascript function is required in order to prevent propagation down when descendant nodes are collapsed.

//--------Override Primefaces JS
PrimeFaces.widget.TreeTable.prototype.fireSelectNodeEvent = function(b) {
    //Overriding this function in order to prevent selection of descendant nodes when parent is selected. See a.oncomplete function below.
    if (this.isCheckboxSelection()) {
           var e = this
             , a = {
               source: this.id,
               process: this.id
           };
           a.params = [{
               name: this.id + "_instantSelection",
               value: b
           }];
           a.oncomplete = function(k, f, g) {
            //commented out the logic to prevent selection of descendant nodes when parent node is selected
            //if (g.descendantRowKeys && g.descendantRowKeys !== "") {
                   //var j = g.descendantRowKeys.split(",");
                   //for (var h = 0; h < j.length; h++) {
                       //e.addToSelection(j[h])
                   //}
                   //e.writeSelections()
               //}
           }
           ;
           if (this.hasBehavior("select")) {
               var d = this.cfg.behaviors.select;
               d.call(this, a)
           } else {
               PrimeFaces.ajax.AjaxRequest(a)
           }
       } else {
           if (this.hasBehavior("select")) {
               var d = this.cfg.behaviors.select
                 , c = {
                   params: [{
                       name: this.id + "_instantSelection",
                       value: b
                   }]
               };
               d.call(this, c)
           }
       }
}

Upvotes: 2

Related Questions