J'utilise mat-tree
avec mat-nested-tree-node
dans Angular 6 . Ce que je veux, c'est charger les données de manière dynamique lorsque l'utilisateur bascule avec l'icône Développer.
Utilisation de l'exemple de données dynamiques de Flat Tree
donné dans Exemples de matériaux J'ai essayé d'utiliser le même concept pour Nested Tree
. C’est ce que j’ai essayé jusqu’à présent https://stackblitz.com/edit/angular-naarcp
Mais il ne montre que les données qui ont été pré-remplies dans le tableau de données bien que dans la console, il est clair que les données sont en train d'être mises à jour mais ne sont jamais affichées sur l'interface utilisateur.
Il appelle de manière récursive la méthode _getChildren
pour les nœuds parent, child1, child2, child3
car il s'agit de données initiales. J'ajoute My Child
dans child1
et child3
lorsque l'utilisateur le développe, mais le nœud ajouté n'est jamais affiché.
Je ne peux pas ajouter d'enfants dynamiques dans _getChildren
car il est appelé récursivement jusqu'au dernier nœud.
Je ne veux pas utiliser Flat tree car il gère tout dans un seul tableau et la mise à jour d'un seul tableau devient vraiment difficile en chargement asynchrone de données
Y at-il quelque chose qui me manque ou des arbres imbriqués sont-ils conçus pour fonctionner de cette façon?
J'ai eu du mal à mettre en œuvre la première version et j'ai constaté que l'interface utilisateur ne se mettait pas à jour car les modifications apportées aux propriétés d'un objet ne sont pas détectées par la détection des modifications. Veuillez lire ma question initiale et y répondre ici. C'est pour un arbre aplati mais peut vous faire économiser des heures de se cogner la tête.
Ajouter Supprimer Élément de mise à jour avec un matériau d'arbre imbriqué angulaire 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;
}