web-dev-qa-db-fra.com

L'arbre imbriqué de 6 matériaux angulaires ne fonctionne pas avec des données dynamiques

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.

Remarque:

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

Aidez-moi 

Y at-il quelque chose qui me manque ou des arbres imbriqués sont-ils conçus pour fonctionner de cette façon?

9
Yousef khan

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.

Pourquoi mon application angulaire devient-elle très lente après la modification des données sauvegardant un arbre mat?

1
Craig

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;
}
0
dheeraj kumar