我正在尝试在Angular 2中实现一个ComponentContainer,以便您可以动态添加其他组件,类似于Android中的LinearLayout。
到目前为止,使用 Angular 2 dynamic tabs with user-click chosen components 我可以动态添加传递Type的组件。
我的问题是使用这个方法,创建的Component只能由它的Type创建,我不知道如何为它提供参数。
这就是我所做的:
container.component.ts
import {
Component,
OnChanges,
AfterViewInit,
OnDestroy,
Input,
Type,
ViewChild,
ViewContainerRef,
ComponentRef,
ComponentResolver,
ComponentFactory
} from '@angular/core';
@Component({
selector: 'wrapper-component',
template: '<div #container></div>'
})
class WrapperComponent implements OnChanges, AfterViewInit, OnDestroy {
@Input() type: Type;
@ViewChild('container', {read: ViewContainerRef}) container;
cmpRef: ComponentRef<any>;
private isViewInitialized: boolean = false;
constructor(private resolver: ComponentResolver) { }
private updateComponent() {
if(!this.isViewInitialized)
return;
if(this.cmpRef)
this.cmpRef.destroy();
this.resolver.resolveComponent(this.type).then((factory: ComponentFactory<any>) => {
this.cmpRef = this.container.createComponent(factory);
})
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef)
this.cmpRef.destroy();
}
}
@Component({
selector: 'container-component',
template: `
<wrapper-component
*ngFor="let element of elements"
[type]="element">
</wrapper-component>
`,
directives: [WrapperComponent]
})
export class ContainerComponent {
private elements: Type[] = [];
visibility: boolean = true;
Add(element: Type) {
this.elements.push(element);
}
AddAll(elements: Type[]) {
elements.forEach(element => {
this.Add(element);
});
}
Clear() {
this.elements = [];
}
}
a1.component.ts
import { Component, Type, ViewChild } from '@angular/core'
import { ContainerComponent } from '../../components/container.component';
@Component({
selector: 'child-component',
template: '<div>a{{text}}</div>'
})
class ChildComponent {
text: string;
}
@Component({
selector: 'a1step',
template: `
<button (click)="onClick()">Add</button>
<container-component #container></container-component>
`,
directives: [ContainerComponent]
})
export class A1Step {
@ViewChild('container') container : ContainerComponent;
onClick() {
this.container.Add(ChildComponent);
}
}
在这里我可以动态添加ChildComponents,但是如何设置其文本?
修改
我不知道是否对其他人有用,但为ChildComponent定义一个参数类,并将ContainerComponent的elements数组更新为包含特定args的对象数组,我可以很容易地将特定参数传递给ChildComponents :
container.component.ts
import {
Component,
OnChanges,
AfterViewInit,
OnDestroy,
Input,
Type,
ViewChild,
ViewContainerRef,
ComponentRef,
ComponentResolver,
ComponentFactory
} from '@angular/core';
export class ChildArgs {
type: Type;
args: any;
}
@Component({
selector: 'wrapper-component',
template: '<div #container></div>'
})
class WrapperComponent implements OnChanges, AfterViewInit, OnDestroy {
@Input() argsElement: ChildArgs;
@ViewChild('container', {read: ViewContainerRef}) container;
cmpRef: ComponentRef<any>;
private isViewInitialized: boolean = false;
constructor(private resolver: ComponentResolver) { }
private updateComponent() {
if(!this.isViewInitialized)
return;
if(this.cmpRef)
this.cmpRef.destroy();
this.resolver.resolveComponent(this.argsElement.type).then((factory: ComponentFactory<any>) => {
this.cmpRef = this.container.createComponent(factory);
this.cmpRef.instance.args = this.argsElement.args;
})
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef)
this.cmpRef.destroy();
}
}
@Component({
selector: 'container-component',
template: `
<wrapper-component
*ngFor="let argsElement of argsElements"
[argsElement]="argsElement">
</wrapper-component>
`,
directives: [WrapperComponent]
})
export class ContainerComponent {
private argsElements: ChildArgs[] = [];
AddArgsElement(argsElement: ChildArgs) {
this.argsElements.push(argsElement);
}
}
a1.component.ts
import { Component, Type, ViewChild } from '@angular/core'
import { ContainerComponent, ChildArgs } from '../../components/container.component';
class ChildComponentArgs {
text: string;
}
@Component({
selector: 'child-component',
template: '<div>a{{args.text}}</div>'
})
class ChildComponent {
args: ChildComponentArgs;
}
class ChildComponent2Args {
text: string;
}
@Component({
selector: 'child-component2',
template: '<div>b{{args.text}}</div>'
})
class ChildComponent2 {
args: ChildComponent2Args;
}
@Component({
selector: 'a1step',
template: `
<button (click)="onClick()">Add</button>
<button (click)="onClick2()">Add2</button>
<container-component #container></container-component>
`,
directives: [ContainerComponent]
})
export class A1Step {
@ViewChild('container') container : ContainerComponent;
private cnt: number = 0;
private cnt2: number = 0;
onClick() {
let childComponentArgs: ChildComponentArgs = new ChildComponentArgs();
childComponentArgs.text = "" + ++this.cnt;
let childArgs: ChildArgs = new ChildArgs();
childArgs.type = ChildComponent;
childArgs.args = childComponentArgs;
this.container.AddArgsElement(childArgs);
}
onClick2() {
let childComponentArgs: ChildComponent2Args = new ChildComponent2Args();
childComponentArgs.text = "" + ++this.cnt2;
let childArgs: ChildArgs = new ChildArgs();
childArgs.type = ChildComponent2;
childArgs.args = childComponentArgs;
this.container.AddArgsElement(childArgs);
}
}
答案 0 :(得分:5)
您可以使用cmpRef.instance
:
this.resolver.resolveComponent(this.type).then((factory: ComponentFactory<any>) => {
this.cmpRef = this.container.createComponent(factory);
this.cmpRef.instance.text = this.someText;
})
另请参阅Angular 2 dynamic tabs with user-click chosen components以获取完整示例。