Angular-tree-component: [HOW TO] Delete a node from a tree

Created on 18 Sep 2017  路  13Comments  路  Source: CirclonGroup/angular-tree-component

I want to delete a node from a tree. Given nodeToDelete, this method doesn't work

The splice method doesn't work, as soon as you call update() the item well be back

const itemIndex = nodeToDelete.index;
nodeToDelete.parent.children.splice(itemIndex, 1); // item disappear
this.tree.treeModel.update(); // item comes back again

If I use the array that I am binding to the tree then I can delete elements from the root as such

const itemIndex = nodeToDelete.index;
this.nodes.splice(itemIndex, 1);
this.tree.treeModel.update();

What if the node I want to delete is not in the root of the nodes array i.e. it is a child of another node?

The first option clearly much better but it doesn't work, the delete is not persisted in the tree.

Most helpful comment

@sulhome

You can try as below

deleteNode(node, tree){
  let parentNode = node.realParent ? node.realParent : node.treeModel.virtualRoot;
        _.remove(parentNode.data.children, function (child) {
            return child === node.data;
        });
        tree.treeModel.update();
        if (node.parent.data.children.length === 0) {
            node.parent.data.hasChildren = false;
        }
  }

and call deleteNode function from your HTML on node.

<tree-root   #tree
      [nodes]="nodes"
      [options]="customTemplateStringOptions">
      <ng-template #treeNodeTemplate let-node>
        <span title="{{node.data.subTitle}}">{{ node.data.name }}</span>
        <span class="pull-right">{{ childrenCount(node) }}</span>
        <button (click)="deleteNode(node, tree)">-</button>
      </ng-template>
      <ng-template #loadingTemplate>Loading, please hold....</ng-template>
 </tree-root>

Hope this will help

Pleas let me know output.

Thanks
Abhi.

All 13 comments

@sulhome

You can try as below

deleteNode(node, tree){
  let parentNode = node.realParent ? node.realParent : node.treeModel.virtualRoot;
        _.remove(parentNode.data.children, function (child) {
            return child === node.data;
        });
        tree.treeModel.update();
        if (node.parent.data.children.length === 0) {
            node.parent.data.hasChildren = false;
        }
  }

and call deleteNode function from your HTML on node.

<tree-root   #tree
      [nodes]="nodes"
      [options]="customTemplateStringOptions">
      <ng-template #treeNodeTemplate let-node>
        <span title="{{node.data.subTitle}}">{{ node.data.name }}</span>
        <span class="pull-right">{{ childrenCount(node) }}</span>
        <button (click)="deleteNode(node, tree)">-</button>
      </ng-template>
      <ng-template #loadingTemplate>Loading, please hold....</ng-template>
 </tree-root>

Hope this will help

Pleas let me know output.

Thanks
Abhi.

@AbhiThakare what is_.remove. I get exception in

Cannot find name '_'.

Thanks

@AbhiThakare

'_' refers to a library called lodash

you need to install it in your angular project then import it like so

import * as _ from 'lodash'

note that the variable name '_' is a convention and you can name it whatever you want

@sulhome , Thanks
I got it. I used import * as _ from 'lodash-es/debounce'; initially, It didn't work.
As you mentioned this worked
import * as _ from 'lodash';

Now is this lodash compatible for AOT ?

@AbhiThakare thanks for your input. I am a complete newbie to this library and would like to understand if there are any documentation that helps me to understand which object has what methods.
As an example, in your code you have fluently written node.realParent, I am curious to understand what is realParent ? I am finding it very difficult to understand the features of this library.
Also why are we doing this?

if (node.parent.data.children.length === 0) {
            node.parent.data.hasChildren = false;
        }

I am trying to write addNode method and I am clueless as to what it should look like. Here is my bad attempt in doing it
addNode(node, tree) { let parentNode = node.realParent ? node.realParent : node.treeModel.virtualRoot; parentNode.children.push({ name: 'new child' }); tree.treeModel.update(); }

@rakesh1988

Thanks!

You can find methods / properties here - https://angular2-tree.readme.io/docs/api
not all is mentioned here, sometime you need to dig into lib code as well.

if (node.parent.data.children.length === 0) {
    node.parent.data.hasChildren = false;
}

This condition is added because, If you delete last child from any parent node then collapse / expand icons should get removed from parent node, in my case it was not working hence added this condition.

As you mention you try to add node, you no need to check for realParent

you can try like below

JS

addNode(node, tree) {    
  tree.treeModel.setFocus(true);
  if (node.data.children === undefined) {
    node.data.children = new Array();
  }
  node.data.children.push({
        name: 'a new child',
        hasChildren: false
    });
  tree.treeModel.update();
}

HTML

<tree-root #tree
      [nodes]="nodes"
      [options]="customTemplateStringOptions">
      <ng-template #treeNodeTemplate let-node>
        <span title="{{node.data.subTitle}}">{{ node.data.name }}</span>
        <span class="pull-right">{{ childrenCount(node) }}</span>
        <button (click)="addNode(node, tree)">+</button>
      </ng-template>
      <ng-template #loadingTemplate>Loading, please hold....</ng-template>
 </tree-root>

Hope this will help

let me know output.

Thanks
Abhi.

Hi,
you should update the original tree and not the wrapped TreeNodes - they get rebuilt from the original nodes on each update

@adamkleingit are you suggesting that the suggested answer is not the right way to do things? can you please give an example about what you are talking about if this is the case

You can use something like this:

deleteNode(node: TreeNode) : void {
    if (node.parent != null) {
        node.parent.data.children.splice(node.parent.data.children.indexOf(node.data), 1)
        this.tree.treeModel.update()
    }
}

you can try this as well
after delete get that node reference again
Node = this.tree.treeModel.getNodeById(someNode.id);
if (parentNode.data.children.length == 0) {
Node.collapseAll();
Node.data.children = null;
Node.data.hasChildren = false;
Node.children = undefined;
this.tree.treeModel.update();
}

There are 2 ways to achieve this:

  • Use immutable data. The tree will automatically recognize the change.
  • Remove the child from the original children list (node.data.children) - not the TreeNode children. And then call update

i search online this project has used add,edit,delete. works good
https://stackblitz.com/edit/github-33gw8i

i search online this project has used add,edit,delete. works good
https://stackblitz.com/edit/github-33gw8i

Hi @vijayuxd Please check back the URL and update it with working on. Thanks :smile:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

JanSchuermannPH picture JanSchuermannPH  路  4Comments

anoop-chauhan picture anoop-chauhan  路  3Comments

thohoh picture thohoh  路  5Comments

BrkCoder picture BrkCoder  路  4Comments

Shadowlauch picture Shadowlauch  路  5Comments