10

I am using the PrimeNG Tree component to enable the users to select some values based on a tree structure. The selected nodes will be later stored in a database and when the user visits the edit dialog again these nodes should be pre selected.

Is there any way to achieve this with the current PrimeNG version? Alternatively it would be nice if you can tell me another angular2 tree component which supports checkbox selection and pre-selection of nodes as well.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Chris S.
  • 323
  • 1
  • 4
  • 13

6 Answers6

9

In selectionMode="checkbox" selected nodes stored in [(selection)]="selectedNodesArray" property.

You can put values from database into selectedNodesArray and this nodes will be selected.

  • Thanks for your answer, now it works! Just learning Angular2 and forgot that it should work this way. Even used this for custom components... :D – Chris S. Mar 01 '17 at 15:04
  • How do you store your tree in database? I'm having problems when i store using post and run Json.stringify () receive error of circular reference because of the parents and children. – Carlinhos Jun 10 '17 at 13:15
  • How does this works in parent child model? I mean if a node has 2 children, 1 is selected and other one's not, on which array the parent should go then? – Ali Baig Nov 19 '17 at 03:14
  • This lets us select a node, but then you can't deselect the node. Is there any way I can remove the selection programatically? – eddy Aug 07 '20 at 23:13
  • @JayeshDhandha The question is about PrimeNG while the issue you linked is a Primefaces ticket. They are not the same – bakcsa83 Jan 02 '22 at 18:53
  • delete by link, sorry for error! – Jayesh Dhandha Jan 03 '22 at 11:23
3

Here is method to select nodes programmatically:

HTML

<p-tree 
  [value]="list['Entities']" 
  [(selection)]="data['Entities']" 
  selectionMode="checkbox">  
</p-tree>

Method

const selectNodes = (tree: TreeNode[], checkedNodes: TreeNode[], keys: string[]) => {
  // Iterate through each node of the tree and select nodes
  let count = tree.length;
  for (const node of tree) {
    // If the current nodes key is in the list of keys to select, or it's parent is selected then select this node as well
    if (keys.includes(node.key) || checkedNodes.includes(node.parent)) {
      checkedNodes.push(node);
      count--;
    }

    // Look at the current node's children as well
    if (node.children)
      selectNodes(node.children, checkedNodes, keys);
  }

  // Once all nodes of a tree are looked at for selection, see if only some nodes are selected and make this node partially selected
  if (tree.length > 0 && tree[0].parent) tree[0].parent.partialSelected = (count > 0 && count != tree.length);
}

Call to the Method

const keysToBeSelected = [2,3,4]
selectNodes(this.list.Entities, this.filterData.Entities, keysToBeSelected);
Nishant
  • 195
  • 1
  • 6
  • 1
    but where does node.parent come from ? In the initial dataset this property is empty but is is "magically" populated after the tree is populated. The first time your code is called, node.parent will be undefined and parents won't be checked. Can you explain how you worked around this ? – Sam Aug 11 '20 at 11:41
2

This is something in between of @Nishant and @Jignesh M. Khatri answer. Node selection works and parent.partialSelected works.

selectNodes(tree: TreeNode[], checkedNodes: TreeNode[], keys: string[]) {
    for (const node of tree) {
        if (keys.includes(node.key) || checkedNodes.includes(node.parent)) {
            checkedNodes.push(node)
        }
        if (node.children)
            this.selectNodes(node.children, checkedNodes, keys)
        this.partialCheckNodes(checkedNodes, node)
    }
}

private partialCheckNodes(checkedNodes: TreeNode[], node: TreeNode) {
    let count = node.children.length
    let c = 0
    for (const childNode of node.children) {
        if (checkedNodes.includes(childNode)) {
            c++
        }
        if (childNode.partialSelected) node.partialSelected = true
    }
    if (c != 0) {
        if (c == count) {
            node.partialSelected = false
            if (!checkedNodes.includes(node)) {
                checkedNodes.push(node)
            }
        } else {
            node.partialSelected = true
        }
    }
}
Mike
  • 920
  • 1
  • 6
  • 12
1

Implement function to find a Node by key

getNodeWithKey(key: string, nodes: TreeNode[]): TreeNode | undefined {
   for (let node of nodes) {
     if (node.key === key) {
        return node;
     }

     if (node.children) {
       let matchedNode = this.getNodeWithKey(key, node.children);
       if (matchedNode) {
         return matchedNode;
       }
     }
   }
   return undefined;
}

Now we are able to easily find the selected nodes based on selected keys, and update the selectedNodes property.

preselectNodes(keys: string[], allNodes: TreeNode[]): void {
    this.selectedNodes = keys.map(key => this.getNodeWithKey(key, allNodes)).filter(this.isTreeNode);
}

The selectedNodes property needs to be assigned in p-tree

<p-tree
  [value]="data"
  selectionMode="multiple"
  [(selection)]="selectedNodes"
  [metaKeySelection]="true"
></p-tree>

isTreeNode is a filter isTreeNode = (item: TreeNode | undefined): item is TreeNode => { return !!item }

Džan Operta
  • 399
  • 2
  • 11
0

Found a workaround for pre-selection of multiple check-boxes (programmatically) in PrimeNG Tree. You can find working example here: https://github.com/jigneshkhatri/primeng-treenode-preselect

Jignesh M. Khatri
  • 1,407
  • 1
  • 14
  • 22
-1

Set the selectionMode attribute of with 'checkbox' like below:

<p-tree
 selectionMode="checkbox"
 [(selection)]="selectedNodes"
  ></p-tree>

The selectedNodes variable contains selected nodes.Add all nodes that you want to be selected in this variable.

Mohammad Niazmand
  • 1,509
  • 9
  • 13