web-dev-qa-db-ja.com

Angular 6 Material Nested Treeは動的データで動作していません

私はmat-treemat-nested-tree-nodeとともにAngular 6.で使用しています。

素材の例 にあるFlat Treeの動的データの例を使用して、Nested Treeにも同じ概念を使用しようとしました。これは私がこれまで試したものです https://stackblitz.com/edit/angular-naarcp

ただし、データ配列に事前入力されたデータのみを表示しますが、コンソールではデータが更新されていることは明らかですが、UIには表示されません。

これは初期データであるため、ノード_getChildrenに対してparent, child1, child2, child3メソッドを再帰的に呼び出します。ユーザーが展開したときに、My Childchild1child3を追加していますが、追加されたノードは表示されません。

最後のノードまで再帰的に呼び出されるため、_getChildrenに動的な子を追加できません。

注意:

フラットツリーはすべてを単一の配列で管理し、データの非同期ロードでは単一の配列の更新が非常に困難になるため、フラットツリーを使用したくない

助けて

欠けているものやネストされたツリーがこのように機能するように設計されているものはありますか?

10
Yousef khan

オブジェクトのプロパティへの変更は変更検出で反映されないため、最初に実装したときに実装し直したときにUIが更新されていないことがわかりました。私の元の質問を読んで、ここに答えてください。平らな木用ですが、頭を叩く時間を節約できます。

なぜmy angular mat-treeをバッキングするデータを変更した後にアプリが非常に遅くなるのですか?

1
Craig

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