Angular 2: Recursive template for child
Asked Answered
I

2

8

The API I am working against gives me the following structure in response:

"data": [
{
  "id": 5,
  "name": "First name",
  "parent": 0
},
{
  "id": 1,
  "name": "Second name",
  "parent": 5
},
{
  "id": 6,
  "name": "Third name",
  "parent": 1
},
{
  "id": 15,
  "name": "Fourth name",
  "parent": 0
},
{
  "id": 25,
  "name": "Fifth name",
  "parent": 5
}
]

I would like to build a tree structure around this using ngFor that supports an unlimited number of children levels.

This is what I have tried so far:

<div *ngFor="let d1 of _dataList">
<ul *ngIf="d1.parent == 0">
    <li>
        {{d1.name}}
        <ul *ngFor="let d2 of _dataList">
            <li *ngIf="d2.parent == d1.id">{{d2.name}}</li>
        </ul>
    </li>
</ul>
</div>

That works, but it's ugly and I have to manually repeat this X-levels down the data and thus leaving a hard-coded limit.

How can one optimize this code to support unlimited levels - and look better?

Intermixture answered 30/1, 2017 at 14:59 Comment(5)
This might help #37747016Inigo
I would rather say it's a duplicateFurore
Possible duplicate of Use component in itself recursively to create a treeFurore
You'll want to format your data and use a recursive structure like the question linked above. You should probably format it so every node that has children has them in an array, and then you can pass data around more easily recursively.Kirit
Thanks Seiyria, I'll look into the possibility of having the API return the list in a different format.Intermixture
O
4

https://stackblitz.com/edit/angular-yij5e5?file=src%2Fapp%2Ftree-view%2Ftree-view.component.ts Note: below code is not recursive it is 2d and can't use for tree render. you should use ng template or defining a component for it.

<div *ngFor="let d1 of _dataList">
<ul *ngIf="d1.parent == 0">
    <li>
        {{d1.name}}
        <ul *ngFor="let d2 of _dataList">
            <li *ngIf="d2.parent == d1.id">{{d2.name}}</li>
        </ul>
    </li>
</ul>
</div>

[Solution 1]=>

JS

let xTree = [{
                "id": 5,
                "name": "First name",
                "parent": 0
            },
            ...
        ];
        let tree = [{
            id: 0,
            name: 'root',
            parent: null,
            childs: []
        }];
        let todoList = [];
        Converter();
        function FindParent(list, el) {
            if (list.length > 0) {
                let res = list.find(x => x.id === el.parent);
                if (res) {
                    return res;
                } else {
                    let _res = undefined;
                    list.forEach(xchild => {
                        _res = FindParent(xchild.childs, el);
                        if (res)
                            return _res;
                    });
                    return _res
                }
            } else {
                return undefined;
            }
        }

        function Converter() {
            todoList = xTree;
            for (let x = 0; x < 90; x++) {
                todoList.forEach(r => {
                    let parent = FindParent(tree, r);
                    if (parent) {
                        if (!parent.childs) {
                            parent.childs = [];
                        }
                        parent.childs.push(r);
                        todoList = todoList.filter(el => el !== r);
                    }
                });
            }
        }

html

<ul class="tree">
  <ng-template #recursiveList let-list="list">
    <li *ngFor="let item of list">
      {{item.name}}
      <ul *ngIf="item.childSet.length > 0">
        <ng-container *ngTemplateOutlet="recursiveList; context:{ list: item.data}"></ng-container>
      </ul>
    </li>
  </ng-template>
  <ng-container *ngTemplateOutlet="recursiveList; context:{ list: data}"></ng-container>
</ul>

css

ul.tree, ul.tree ul {
  list-style-type: none;
}
  ul.tree, ul.tree ul {
    list-style-type: none;
    background: url(/assets/vline.png) repeat-y;
    margin: 0;
    padding: 0;
  }

    ul.tree ul {
      margin-left: 10px;
    }

    ul.tree li {
      margin: 0;
      padding: 0 12px;
      line-height: 20px;
      background: url(/assets/node.png) no-repeat;
      color: #369;
      font-weight: bold;
    }

      ul.tree li:last-child {
        background: #fff url(/assets/lastnode.png) no-repeat;
      }
Oily answered 21/8, 2018 at 23:52 Comment(0)
L
3

you can have a recusive component, say the component called TreeComponent and the template for TreeComponent will be like this

<div *ngFor="let item of dataList">
  <ul *ngIf="item.parent==parentId">
    <li>{{item.name}}
      <tree [parentId]="item.id" [dataList]="removeCurrentLevelItems(dataList,parentId)"></tree>
    </li>
  </ul>
</div>

check the link here for a live demo

Lukin answered 22/8, 2018 at 0:47 Comment(2)
hi, lucas, I can not find a way to do editing from the live demo link. Could you please help ?Exeter
@FengZhang it doesnt require permissions etc to do editing, you can try to fork to your one or check your browser console to see any errorsLukin

© 2022 - 2024 — McMap. All rights reserved.