【问题标题】:Angular2 component treeAngular2 组件树
【发布时间】:2016-05-02 09:46:47
【问题描述】:

我从第一个 Alpha 版开始就一直在使用 Angular 2,但我一直坚持从组件创建可遍历树。

我有单独的组件配置和设置数据源,这些数据源是持久的,并且还会对关联组件的某些事件做出反应。此源是由视图中的角度组件表示的树。树节点与角度组件树完全匹配。

Components 继承自同一个抽象类 BaseComponent。组件可以包含任意数量的 BaseComponent 子实例,因此它不知道父/子的确切类型。

我想避免通过组件输入指定某种键。

有什么方法可以使用基类型获取父级吗?

TL;DR:我需要在不知道确切类型的情况下构建以下组件的父/子树

export abstract class BaseComponent {
    public children: Array<BaseComponent>;

    constructor(
         //I need something like this but it's not working for ancestor classes
         @Inject(forwardRef(() => BaseComponent))
         private _parent: BaseComponent)
    {
         _parent.children.push(this);
    }
}

@Component({...})
export class A extends BaseComponent {...}

@Component({...})
export class B extends BaseComponent {...}

@Component({...})
export class C extends BaseComponent {...}

@Component({...})
export class D extends BaseComponent {...}

【问题讨论】:

  • 如何创建树?您是使用*ngFor 为模型中的数据呈现项目,还是这些项目是由 DOM 树创建的,例如 &lt;a-comp&gt;&lt;b-comp&gt;&lt;/b-comp&gt;&lt;b-comp&gt;&lt;c-comp&gt;&lt;/c-comp&gt;&lt;/b-comp&gt;&lt;/a-comp&gt;
  • 它们是由 DOM 树创建的,*ngFor 在内部的一些组件中使用。
  • 所以孩子们使用&lt;ng-content&gt;进行投影?

标签: typescript angular


【解决方案1】:

我很确定没有办法做你想做的事。
Angulars DI 不支持基类注入。

另一种方法是将所有这些类型组合到一个组件中,并使用例如ngSwitch 来选择应显示的视图的不同部分,具体取决于用于在具体类型之间切换的某些指标节点。

Plunker example

【讨论】:

  • 感谢您的想法,但有许多组件继承自基本类型,因此在多个地方使用一个大开关不是一种选择
  • 另一种选择是使用 DynamicComponentLoader,就像在 stackoverflow.com/questions/36325212/… 中演示的那样,根据某些值将具体类型添加到 DOM。
  • 这是一个有效的选项,不幸的是,这意味着我必须手动管理创建和销毁子组件(更不用说更改检测),如果可能的话我想避免。
  • 不确定你的意思。 dcl-wrapper 组件会为您做到这一点。
  • 对不起,我错过了 onchanges 方法,但这仍然不能管理加载组件的输入和输出
【解决方案2】:

在 beta.17 中有一个使用 ElementInjector 的解决方法,它作为 Injector 自动注入到组件中,请参见下面的代码:

constructor(injector: Injector){
    var parent = injector._view.context;
}

【讨论】:

    【解决方案3】:

    前段时间我做了一个简单的树组件。

    • tree-node.ts 等同于您的基类。

    • tree-node.com.ts 是一个演示组件。它使用递归模板来显示树。

    Plunker:http://plnkr.co/zsDbGp

    tree-node.com.ts

    import { Component, OnInit, Input } from '@angular/core';
    
    import { TreeNode } from './tree-node';
    
    @Component({
    	selector: 'tree-node-com',
    	template: `
    		<div *ngIf="root">{{title}}</div>
    		<ul>{{tree.e}}({{tree.size()}})
    			<li *ngFor="let n of tree.c">
    				<tree-node-com [tree]="n"></tree-node-com>
    			</li>
    		</ul>`
    })
    export class TreeNodeCom implements OnInit {
    	title: string = 'Tree - Tree Structure';
    
    	@Input() tree;
    	root: boolean = false;
    
    	constructor() { }
    
    	ngOnInit() {
    		if (!this.tree) {
    			this.root = true;
    			this.tree = new TreeNode('/');
    			this.initTree();
    		}
    		this.tree.log();
    	}
    
    	initTree() {
    		// Create 2 level of node
    		for (let i = 0; i < 5; i++) {
    			let n = this.tree.add(`${i}`);
    			for (let j = 0; j < 5; j++) {
    				n.add(j);
    			}
    		}
    	}
    }

    树节点.ts

    export class TreeNode {
    	// Parent Node
    	p: TreeNode;
    	// Children Node
    	c: TreeNode[];
    	// Element
    	e: any;
    	// Number of element in tree
    	private n: number;
    
    	constructor(e: any) {
    		this.p = undefined;
    		this.e = e;
    		this.n = 1;
    		this.c = [];
    	}
    
    	toString(): string {
    		if (typeof (this.e) === 'string') {
    			return this.e;
    		}
    		return this.e.toString();
    	}
    
    	equals(n: TreeNode): boolean {
    		if (typeof n.e !== typeof this.e) {
    			return false;
    		}
    		return (n.e.toString() === this.e.toString());
    	}
    
    	/*
    	* Add a child node 
    	*/
    	add(e: any): TreeNode {
    		let n = new TreeNode(e);
    		n.n = 1;
    		return this.addNode(n);
    	}
    	addNode(n: TreeNode): TreeNode {
    		n.p = this;
    		this.c.push(n);
    		this.updateN(n.size());
    		return n;
    	}
    	addToPath(e: any, p: string): TreeNode {
    		let n = new TreeNode(e);
    		return this.addNodeToPath(n, p);
    	}
    	addNodeToPath(n: TreeNode, p: string): TreeNode {
    		// Place holder
    		return n;
    	}
    
    	/*
    	* Delete child node 
    	*/
    	del(e: any): boolean { return true; }
    	delNode(n: TreeNode): boolean {
    		this.updateN(-n.size());
    		return true;
    	}
    	delToPath(p: string): boolean {
    		// Place holder
    		return true;
    	}
    	delAll(): void {
    		this.c = [];
    	}
    
    	/*
    	* Get full path of this node 
    	*/
    	get(path: string): TreeNode {
    		let node: TreeNode = undefined;
    		return node;
    	}
    
    	size(): number {
    		return this.n;
    	}
    
    	updateN(n: number) {
    		this.n += n;
    		if (this.p) {
    			this.p.updateN(n);
    		}
    	}
    
    	log() {
    		this.printTree(this, 0);
    	}
    	private printTree(n: TreeNode, t: number) {
    		let tab = '';
    		for (let i = 0; i < t; i++) {
    			tab += '\t';
    		}
    		// Print myself
    		console.log(`${tab}${n.e}(${n.size()})`);
    		// Print children
    		if (n.c) {
    			n.c.forEach(j => this.printTree(j, t + 1));
    		}
    	}
    }

    另类

    你也可以像https://angular2-tree.readme.io/docs这样探索第三方库

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-11
      • 1970-01-01
      • 2016-07-02
      • 2017-07-22
      • 2016-03-01
      • 2017-02-06
      • 2017-08-16
      相关资源
      最近更新 更多