组件代码为:
import {CollectionViewer, SelectionChange} from '@angular/cdk/collections';
import {FlatTreeControl} from '@angular/cdk/tree';
import {Component, Injectable} from '@angular/core';
import {BehaviorSubject, merge, Observable} from 'rxjs';
import {map} from 'rxjs/operators';
/** Flat node with expandable and level information */
export class DynamicFlatNode {
constructor(public item: string, public level = 1, public expandable = false,
public isLoading = false) {}
}
/**
* Database for dynamic data. When expanding a node in the tree, the data source will need to fetch
* the descendants data from the database.
*/
export class DynamicDatabase {
dataMap = new Map<string, string[]>([
['Fruits', ['Apple', 'Orange', 'Banana']],
['Vegetables', ['Tomato', 'Potato', 'Onion']],
['Apple', ['Fuji', 'Macintosh']],
['Onion', ['Yellow', 'White', 'Purple']]
]);
rootLevelNodes: string[] = ['Fruits', 'Vegetables'];
/** Initial data from database */
initialData(): DynamicFlatNode[] {
return this.rootLevelNodes.map(name => new DynamicFlatNode(name, 0, true));
}
getChildren(node: string): string[] | undefined {
return this.dataMap.get(node);
}
isExpandable(node: string): boolean {
return this.dataMap.has(node);
}
}
/**
* File database, it can build a tree structured Json object from string.
* Each node in Json object represents a file or a directory. For a file, it has filename and type.
* For a directory, it has filename and children (a list of files or directories).
* The input will be a json object string, and the output is a list of `FileNode` with nested
* structure.
*/
@Injectable()
export class DynamicDataSource {
dataChange = new BehaviorSubject<DynamicFlatNode[]>([]);
get data(): DynamicFlatNode[] { return this.dataChange.value; }
set data(value: DynamicFlatNode[]) {
this._treeControl.dataNodes = value;
this.dataChange.next(value);
}
constructor(private _treeControl: FlatTreeControl<DynamicFlatNode>,
private _database: DynamicDatabase) {}
connect(collectionViewer: CollectionViewer): Observable<DynamicFlatNode[]> {
this._treeControl.expansionModel.onChange.subscribe(change => {
if ((change as SelectionChange<DynamicFlatNode>).added ||
(change as SelectionChange<DynamicFlatNode>).removed) {
this.handleTreeControl(change as SelectionChange<DynamicFlatNode>);
}
});
return merge(collectionViewer.viewChange, this.dataChange).pipe(map(() => this.data));
}
/** Handle expand/collapse behaviors */
handleTreeControl(change: SelectionChange<DynamicFlatNode>) {
if (change.added) {
change.added.forEach(node => this.toggleNode(node, true));
}
if (change.removed) {
change.removed.slice().reverse().forEach(node => this.toggleNode(node, false));
}
}
/**
* Toggle the node, remove from display list
*/
toggleNode(node: DynamicFlatNode, expand: boolean) {
const children = this._database.getChildren(node.item);
const index = this.data.indexOf(node);
if (!children || index < 0) { // If no children, or cannot find the node, no op
return;
}
node.isLoading = true;
setTimeout(() => {
if (expand) {
const nodes = children.map(name =>
new DynamicFlatNode(name, node.level + 1, this._database.isExpandable(name)));
this.data.splice(index + 1, 0, ...nodes);
} else {
let count = 0;
for (let i = index + 1; i < this.data.length
&& this.data[i].level > node.level; i++, count++) {}
this.data.splice(index + 1, count);
}
// notify the change
this.dataChange.next(this.data);
node.isLoading = false;
}, 1000);
}
}
/**
* @title Tree with dynamic data
*/
@Component({
selector: 'tree-dynamic-example',
templateUrl: 'tree-dynamic-example.html',
styleUrls: ['tree-dynamic-example.css'],
providers: [DynamicDatabase]
})
export class TreeDynamicExample {
constructor(database: DynamicDatabase) {
this.treeControl = new FlatTreeControl<DynamicFlatNode>(this.getLevel, this.isExpandable);
this.dataSource = new DynamicDataSource(this.treeControl, database);
this.dataSource.data = database.initialData();
}
treeControl: FlatTreeControl<DynamicFlatNode>;
dataSource: DynamicDataSource;
getLevel = (node: DynamicFlatNode) => node.level;
isExpandable = (node: DynamicFlatNode) => node.expandable;
hasChild = (_: number, _nodeData: DynamicFlatNode) => _nodeData.expandable;
}
数据源是类DynamicDatabase
。它是Map对象,具有设置/获取方法。
我试图通过键Fruits
添加一个新的节点元素:
this.database.dataMap.set('Fruits', ['A', 'B']);
但是它改写了旧值,
['Fruits', ['Apple', 'Orange', 'Banana', 'A', 'B']]
我也可以这样做:
this.dataSource.data = [new DynamicFlatNode('Papa', 0, true)];
但是作用相同
答案 0 :(得分:1)
您可以尝试以下操作:
const updatedData = [...this.database.dataMap.get('Fruits'), 'A', 'B'];
this.database.dataMap.set('Fruits', updatedData);
但是,如果有可能,您可以将其更改为简单的js object
并与对象一起使用,而不是Map