typescript Angular 6 Material Nested Tree 不适用于动态数据
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/51764673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Angular 6 Material Nested Tree is not working with dynamic data
提问by Yousef khan
I am using mat-tree
with mat-nested-tree-node
in Angular 6.
What I want is to load the data dynamically when the user toggles expand icon.
我在 Angular 6 中使用mat-tree
with mat-nested-tree-node
。我想要的是在用户切换展开图标时动态加载数据。
Using the dynamic data example of Flat Tree
given in Material ExamplesI have tried to use the same concept for Nested Tree
. This is what I have tried so far https://stackblitz.com/edit/angular-naarcp
使用材料示例中Flat Tree
给出的动态数据示例,我尝试将相同的概念用于. 这是我到目前为止尝试过的https://stackblitz.com/edit/angular-naarcpNested Tree
But it only shows the data which was prepopulated in the data array although in the console it is clear that data is getting updated but it never gets shown on the UI.
但它只显示预先填充在数据数组中的数据,尽管在控制台中很明显数据正在更新,但它从未显示在 UI 上。
It recursively calls the _getChildren
method for the nodes parent, child1, child2, child3
because this is initial data. I am adding My Child
in child1
and child3
when user expands it but the added node is never shown.
它递归地调用_getChildren
节点的方法,parent, child1, child2, child3
因为这是初始数据。我加入My Child
中child1
和child3
当用户展开,但从未中所示的添加节点。
I can not add dynamic children in _getChildren
because it gets called recursively till last node.
我无法添加动态子项,_getChildren
因为它会被递归调用直到最后一个节点。
Note:
笔记:
I dont want to use Flat tree because it manages everything in single array and updating the single array gets really difficult in asynchronous loading of data
我不想使用平面树,因为它管理单个数组中的所有内容,并且在异步加载数据时更新单个数组变得非常困难
Help
帮助
Is there anything I am missing or nested trees are designed to work this way?
有什么我遗漏的或嵌套的树旨在以这种方式工作吗?
回答by Craig
I struggled when I implemented back when it first came out and found the UI wasnt updating because changes to an objects's properties do not get picked up by change detection. Please read through my original question and answer here. It is for a flattened tree but might save you hours of banging your head.
当我在它第一次出现时重新实现并发现 UI 没有更新时,我很挣扎,因为更改检测没有检测到对对象属性的更改。请阅读我的原始问题并在此处回答。它适用于一棵扁平的树,但可能会为您节省数小时的敲头时间。
Why is my angular app becoming very slow after changing the data backing a mat-tree?
回答by dheeraj kumar
Add Remove Update element with Angular 6 Nested Tree Material
使用 Angular 6 嵌套树材质添加移除更新元素
addmodifymilestone.component.ts
addmodifymilestone.component.ts
import { Component, Injectable, AfterViewInit, ViewChild } from '@angular/core';
import { NestedTreeControl } from '@angular/cdk/tree';
import { MatTreeNestedDataSource } from '@angular/material/tree';
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
/**
* Json node data with nested structure. Each node has a filename and a value or a list of children
*/
export class ItemNode {
children: ItemNode[];
filename: string;
type: any;
expanded: boolean;
}
@Component({
selector: 'app-addmodifymilestone',
templateUrl: './addmodifymilestone.component.html',
styleUrls: ['./addmodifymilestone.component.scss'],
})
export class AddmodifymilestoneComponent implements AfterViewInit {
@ViewChild('tree') tree;
updateNodeItemName: any = 'null';
updateItemNameInput: any;
nestedTreeControl: NestedTreeControl<ItemNode>;
nestedDataSource: MatTreeNestedDataSource<ItemNode>;
dataChange: BehaviorSubject<ItemNode[]> = new BehaviorSubject<ItemNode[]>([]);
constructor() {
this.nestedTreeControl = new NestedTreeControl<ItemNode>(this._getChildren);
this.nestedDataSource = new MatTreeNestedDataSource();
this.dataChange.subscribe(data => this.nestedDataSource.data = data);
this.dataChange.next([
// {
// filename: 'Milestones',
// type: '',
// 'expanded': false,
// children: [
// {
// filename: 'Milestone1',
// type: '',
// 'expanded': false,
// children: []
// }
// ]
// }
]);
// this.dataChange.next([
// {
// filename: 'Milestones',
// type: '',
// children: [
// {
// filename: 'Milestone1',
// type: '',
// children: [
// {
// filename: 'To do list',
// type: '',
// children: [
// {
// filename: 'Suggestion',
// type: 'suggetion1, suggestion 2',
// children: []
// }
// ],
// },
// ],
// }
// ],
// },
// ]);
}
private _getChildren = (node: ItemNode) => {
return observableOf(node.children);
}
hasNestedChild = (_: number, nodeData: ItemNode) => {
return !(nodeData.type);
}
ngAfterViewInit(): void {
this.nestedTreeControl = new NestedTreeControl<ItemNode>(this._getChildren);
this.nestedDataSource = new MatTreeNestedDataSource();
this.dataChange.subscribe(data => this.nestedDataSource.data = data);
}
changeState(node) {
console.log('change state called :::');
node.expanded = !node.expanded;
console.log(node);
}
addNewMilestone() {
this.nestedTreeControl = new NestedTreeControl<ItemNode>(this._getChildren);
this.nestedDataSource = new MatTreeNestedDataSource();
this.dataChange.subscribe(data => this.nestedDataSource.data = data);
let tempData: any[];
this.dataChange.subscribe(data => tempData = data);
const data = new ItemNode();
data.filename = 'New Milestone';
data.type = '',
data.children = [
{
filename: 'AddToDoList',
type: 'AddToDoList',
'expanded': false,
children: [],
},
{
filename: 'To do list',
type: '',
'expanded': false,
children: [
{
filename: 'AddSuggestion',
type: 'AddSuggestion',
'expanded': false,
children: [],
},
{
filename: 'suggestions',
type: 'suggestion1, suggestion2, suggestion3',
'expanded': false,
children: []
},
],
},
];
tempData.push(data);
this.dataChange.next(tempData);
}
addNewToDoList(node: ItemNode) {
this.nestedTreeControl = new NestedTreeControl<ItemNode>(this._getChildren);
this.nestedDataSource = new MatTreeNestedDataSource();
this.dataChange.subscribe(data => this.nestedDataSource.data = data);
const nodeChiledren: any[] = node.children;
const data = {
filename: 'To do list',
type: '',
children: [
{
filename: 'AddSuggestion',
type: 'AddSuggestion',
'expanded': false,
children: [],
}
],
};
nodeChiledren.push(data);
let tempData: any[];
this.dataChange.subscribe(data => tempData = data);
tempData = tempData.map((value, index, array) => {
if (value.filename === node.filename) {
value.children = nodeChiledren;
}
return value;
});
const dataStringfy = JSON.stringify(tempData);
const json: ItemNode[] = JSON.parse(dataStringfy);
this.dataChange.next(json);
}
addNewSuggestion(node: ItemNode) {
this.nestedTreeControl = new NestedTreeControl<ItemNode>(this._getChildren);
this.nestedDataSource = new MatTreeNestedDataSource();
this.dataChange.subscribe(data => this.nestedDataSource.data = data);
const nodeChiledren: any[] = node.children;
const data = {
filename: 'Suggestion',
type: 'suggestion11, suggestion22',
'expanded': false,
children: [],
};
nodeChiledren.push(data);
let tempData: any[];
this.dataChange.subscribe(data => tempData = data);
tempData = tempData.map((value, index, array) => {
if (value.filename === node.filename) {
value.children = nodeChiledren;
}
return value;
});
const dataStringfy = JSON.stringify(tempData);
const json: ItemNode[] = JSON.parse(dataStringfy);
this.dataChange.next(json);
}
enableUpdateNode(node: ItemNode) {
console.log('updateNode :::');
console.log(node);
this.updateNodeItemName = node.filename;
}
updateNode(node: ItemNode) {
this.updateNodeItemName = 'null';
console.log(this.updateItemNameInput);
console.log(node);
this.nestedTreeControl = new NestedTreeControl<ItemNode>(this._getChildren);
this.nestedDataSource = new MatTreeNestedDataSource();
this.dataChange.subscribe(data => this.nestedDataSource.data = data);
node.filename = this.updateItemNameInput;
let tempData: any[];
this.dataChange.subscribe(data => tempData = data);
tempData = tempData.map((value, index, array) => {
if (value.filename === node.filename) {
value = node;
}
return value;
});
const dataStringfy = JSON.stringify(tempData);
const json: ItemNode[] = JSON.parse(dataStringfy);
this.dataChange.next(json);
}
deleteNode(node: any) {
this.nestedTreeControl = new NestedTreeControl<ItemNode>(this._getChildren);
this.nestedDataSource = new MatTreeNestedDataSource();
this.dataChange.subscribe(data => this.nestedDataSource.data = data);
node.filename = this.updateItemNameInput;
let tempData: any[];
this.dataChange.subscribe(data => tempData = data);
const index = tempData.findIndex(value => value.filename === node.filename);
tempData.splice(index, 1);
const dataStringfy = JSON.stringify(tempData);
const json: ItemNode[] = JSON.parse(dataStringfy);
this.dataChange.next(json);
}
}
addmodifymilestone.component.html
addmodifymilestone.component.html
<p class="paragraphMargingLeft">Add New Milestone <i class="fa fa-plus-square" aria-hidden="true" (click)="addNewMilestone()"></i></p>
<mat-tree #tree [dataSource]="nestedDataSource" [treeControl]="nestedTreeControl" class="example-tree">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
<li class="mat-tree-node" *ngIf="node.filename !== 'AddToDoList' && node.filename !== 'AddSuggestion'">
<button mat-icon-button disabled></button>
{{node.filename}}: {{node.type }}
<i class="fa fa fa-pencil" aria-hidden="true"></i>
<i class="fa fa-trash" aria-hidden="true"></i>
</li>
</mat-tree-node>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
<!-- {{node | json}} -->
<li>
<div class="mat-tree-node">
<button mat-icon-button [attr.aria-label]="'toggle ' + node.name" (click)="changeState(node)">
<mat-icon class="mat-icon-rtl-mirror">
{{node.expanded ? 'expand_more' : 'chevron_right'}}
</mat-icon>
</button>
<div *ngIf="updateNodeItemName !== node.filename else updateable">
{{node.filename}}
</div>
<ng-template #updateable>
<mat-form-field>
<input matInput [(ngModel)]="updateItemNameInput" (change)="updateNode(node)" placeholder="Update Item">
</mat-form-field>
</ng-template>
<i class="fa fa fa-pencil" aria-hidden="true" (click)="enableUpdateNode(node)"></i>
<i class="fa fa-trash" aria-hidden="true" (click)="deleteNode(node)"></i>
<!-- <button mat-icon-button (click)="addNewItem(node)"><mat-icon>add</mat-icon></button> -->
</div>
<ul [class.example-tree-invisible]="node.expanded">
<div *ngFor="let data of node.children">
<div *ngIf="data.filename === 'AddToDoList'">
<p class="paragraphMargingLeft">Add To do list <i class="fa fa-plus-square" aria-hidden="true" (click)="addNewToDoList(node)"></i></p>
</div>
<div *ngIf="data.filename === 'AddSuggestion'">
<p class="paragraphMargingLeft">Add Suggestion<i class="fa fa-plus-square" aria-hidden="true" (click)="addNewSuggestion(node)"></i></p>
</div>
</div>
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
addmodifymilestone.component.scss
addmodifymilestone.component.scss
.example-tree-invisible {
display: none;
}
.example-tree ul,
.example-tree li {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
.example-tree li {
margin-left: 25px;
}
.fa {
margin:5px;
}
.fa-trash{
color: red;
}
.mat-tree-node {
display: flex;
align-items: center;
min-height: 0px;
flex: 1;
overflow: hidden;
word-wrap: break-word;
}
.paragraphMargingLeft{
margin-left: 46px;
}