私はmat-tree
をmat-nested-tree-node
とともにAngular 6.で使用しています。
素材の例 にあるFlat Tree
の動的データの例を使用して、Nested Tree
にも同じ概念を使用しようとしました。これは私がこれまで試したものです https://stackblitz.com/edit/angular-naarcp
ただし、データ配列に事前入力されたデータのみを表示しますが、コンソールではデータが更新されていることは明らかですが、UIには表示されません。
これは初期データであるため、ノード_getChildren
に対してparent, child1, child2, child3
メソッドを再帰的に呼び出します。ユーザーが展開したときに、My Child
とchild1
にchild3
を追加していますが、追加されたノードは表示されません。
最後のノードまで再帰的に呼び出されるため、_getChildren
に動的な子を追加できません。
フラットツリーはすべてを単一の配列で管理し、データの非同期ロードでは単一の配列の更新が非常に困難になるため、フラットツリーを使用したくない
欠けているものやネストされたツリーがこのように機能するように設計されているものはありますか?
オブジェクトのプロパティへの変更は変更検出で反映されないため、最初に実装したときに実装し直したときにUIが更新されていないことがわかりました。私の元の質問を読んで、ここに答えてください。平らな木用ですが、頭を叩く時間を節約できます。
Angular 6ネストされたツリーマテリアル
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
<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
.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;
}