Mat-tree:动态数据-组件UI不更新

时间:2019-03-29 15:17:59

标签: angular angular-material

在支持带有动态数据的嵌套mat-tree的实现中,我可以看到在展开树项时正在加载数据,但是子项从未得到渲染。

我从Angular Material的文档中获取了示例代码,并尝试根据自己的需要进行调整。不幸的是,我不能说我完全理解那里发生的事情,因此我一直无法解决问题。

主要成分:

export class TrackableBrowserComponent {
  nestedTreeControl: NestedTreeControl<CategoryNode>;
  nestedDataSource: CategoryDataSource;

  hasNestedChild = (_: number, node: CategoryNode) => true;
  getChildren = (node: CategoryNode) => node.children;

  constructor(categoryService: CategoryService) {
    this.nestedTreeControl = new NestedTreeControl<CategoryNode>(this.getChildren);
    this.nestedDataSource = new CategoryDataSource(categoryService, this.nestedTreeControl);
  }
}

mat树的渲染方式如下:

<mat-tree [dataSource]="nestedDataSource" [treeControl]="nestedTreeControl" class="example-tree">
  <mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
    <li class="mat-tree-node">
      <button mat-icon-button disabled></button>
      {{node.name}}:  {{node.type}}
    </li>
  </mat-tree-node>
  <mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
    <li>
      <div class="mat-tree-node">
        <button mat-icon-button matTreeNodeToggle>
          <mat-icon class="mat-icon-rtl-mirror">{{nestedTreeControl.isExpanded(node) ? 'expand_more' : 'chevron_right'}}</mat-icon>
        </button>
        {{node.name}}
      </div>
      <ul [class.example-tree-invisible]="!nestedTreeControl.isExpanded(node)">
        <ng-container matTreeNodeOutlet></ng-container>
      </ul>
    </li>
  </mat-nested-tree-node>
</mat-tree>

这是可能包含问题的部分。

export class CategoryNode {
    name: string;
    description: string;
    children: CategoryNode[] = [];
    category: Category;

    static from(category: Category): CategoryNode {
        const n = new CategoryNode();
        n.name = category.name;
        n.category = category;
        n.children = [];
        return n;
    }
}

export class CategoryDataSource implements DataSource<CategoryNode> {

    dataChange: BehaviorSubject<CategoryNode[]> = new BehaviorSubject<CategoryNode[]>([]);

    constructor(
        private categoryService: CategoryService,
        private treeControl: NestedTreeControl<CategoryNode>
    ) {
        this.categoryService.getAll().pipe(
            map(categories => categories.map(c => CategoryNode.from(c)))
        ).subscribe(nodes => this.data = nodes);
    }

    connect(collectionViewer: CollectionViewer): Observable<CategoryNode[]> {
        console.log('collect(): called');
        this.treeControl.expansionModel.changed.subscribe(change => {
            console.log('collect(): received change event from treeControl.expansionModel');
            if ((change as SelectionChange<CategoryNode>).added ||
                (change as SelectionChange<CategoryNode>).removed) {
                this.handleTreeControl(change as SelectionChange<CategoryNode>);
            }
        });

        return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
    }

    disconnect(collectionViewer: CollectionViewer): void {
        throw new Error('Method not implemented.');
    }

    get data(): CategoryNode[] {
        return this.dataChange.value;
    }

    set data(value: CategoryNode[]) {
        this.treeControl.dataNodes = value;
        this.dataChange.next(value);
    }

    handleTreeControl(change: SelectionChange<CategoryNode>) {
        if (change.added) {
            console.log('handleTreeControl(): added');
            change.added.forEach(node => this.toggleNode(node, true));
        } else if (change.removed) {
            console.log('handleTreeControl(): removed');
            change.removed.slice().reverse().forEach(node => this.toggleNode(node, false));
        } else {
            console.log('handleTreeControl(): other');
        }
    }

    toggleNode(node: CategoryNode, expand: boolean) {
        console.log('toggleNode(): called');
        if (expand === true) {
            console.log('toggleNode(): expanding node ' + node.name);
            node.category.children.pipe(map(all => all.map(item => CategoryNode.from(item)))).subscribe(nodes => {
                console.log('toggleNode(): received data ' + JSON.stringify(nodes));
                node.children = nodes;
                this.treeControl.dataNodes = this.data;
                this.dataChange.next(this.data);
            });
        }
    }
}

我需要补充一点,我的Category实体具有一个名为“ children”的ReplaySubject,该实体将向后端API触发GET / cartegories / ID / children调用。

export class Category extends BaseEntity<CategoryLinks> {
  name: string;
  description: string;
  parent: ReplaySubject<Category>;
  children: ReplaySubject<Category[]>;
}

我的总体想法是在展开项目时将Category中的CategoryNode变形并将ReplaySubject的结果复制到CategoryNode的“ children”属性中。这部分似乎有效,因为我可以看到

的输出
console.log('toggleNode(): received data ' + JSON.stringify(nodes));

在浏览器日志中。

我认为现在连接到该DataSource的任何人都应得到有关该更改的通知,并相应地进行更新。但这不会发生。我按了树上的扩展按钮,触发了后端调用,但是UI中什么也没发生。

有什么想法吗?

0 个答案:

没有答案