Angular 6材质嵌套树不适用于动态数据

时间:2018-08-09 10:30:54

标签: angular typescript angular-material2

我在Angular 6中将mat-treemat-nested-tree-node一起使用。 我想要的是在用户切换展开图标时动态加载数据。

使用Material Examples中给出的Flat Tree的动态数据示例,我尝试对Nested Tree使用相同的概念。这是我到目前为止尝试过的https://stackblitz.com/edit/angular-naarcp

但是它只显示预先填充在数据数组中的数据,尽管在控制台中很明显数据正在更新,但从未显示在UI上。

它为节点_getChildren递归调用parent, child1, child2, child3方法,因为这是初始数据。我在用户展开时在My Childchild1中添加child3,但是从未显示添加的节点。

我无法在_getChildren中添加动态子级,因为它会递归地调用到最后一个节点。

注意:

我不想使用Flat tree,因为它可以管理单个数组中的所有内容,并且在异步加载数据时更新单个数组真的很困难

帮助

有什么我想念的东西吗?还是嵌套树被设计为以这种方式工作?

2 个答案:

答案 0 :(得分:1)

当我第一次实现它时发现它并没有更新,这是我的努力,因为对对象属性的更改不会被更改检测所吸收。请仔细阅读我的原始问题并在此处回答。它是用于平整的树,但是可以节省数小时的敲打头。

Why is my angular app becoming very slow after changing the data backing a mat-tree?

答案 1 :(得分:0)

添加带有Angular 6嵌套树材质的Remove Update元素

addmodifymilestone.component.ts

var
  GPGraphics: TGPGraphics;
begin
  GPGraphics.DrawImage(headingGPImage, slider3.Position * 4, 200);
end;

addmodifymilestone.component.html

    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.scss

<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>