更新
Angular 5 StackBlitz示例
更新
ngComponentOutlet
被添加到4.0.0-beta.3
更新
NgComponentOutlet
正在进行中的工作正在执行类似https://github.com/angular/angular/pull/11235的工作
RC.7
柱塞示例RC.7
// Helper component to add dynamic components
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
@ViewChild('target', {read: ViewContainerRef}) target: ViewContainerRef;
@Input() type: Type<Component>;
cmpRef: ComponentRef<Component>;
private isViewInitialized:boolean = false;
constructor(private componentFactoryResolver: ComponentFactoryResolver, private compiler: Compiler) {}
updateComponent() {
if(!this.isViewInitialized) {
return;
}
if(this.cmpRef) {
// when the `type` input changes we destroy a previously
// created component before creating the new one
this.cmpRef.destroy();
}
let factory = this.componentFactoryResolver.resolveComponentFactory(this.type);
this.cmpRef = this.target.createComponent(factory)
// to access the created instance use
// this.compRef.instance.someProperty = 'someValue';
// this.compRef.instance.someOutput.subscribe(val => doSomething());
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
使用范例
// Use dcl-wrapper component
@Component({
selector: 'my-tabs',
template: `
<h2>Tabs</h2>
<div *ngFor="let tab of tabs">
<dcl-wrapper [type]="tab"></dcl-wrapper>
</div>
`
})
export class Tabs {
@Input() tabs;
}
@Component({
selector: 'my-app',
template: `
<h2>Hello {{name}}</h2>
<my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
// The list of components to create tabs from
types = [C3, C1, C2, C3, C3, C1, C1];
}
@NgModule({
imports: [ BrowserModule ],
declarations: [ App, DclWrapper, Tabs, C1, C2, C3],
entryComponents: [C1, C2, C3],
bootstrap: [ App ]
})
export class AppModule {}
另请参见angular.io动态组件加载器
旧版本 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Angular2 RC.5中再次改变了这一点
我将更新以下示例,但这是放假前的最后一天。
此柱塞示例演示了如何在RC.5中动态创建组件。
更新-使用ViewContainerRef .createComponent()
由于DynamicComponentLoader
已弃用,因此该方法需要再次更新。
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
@ViewChild('target', {read: ViewContainerRef}) target;
@Input() type;
cmpRef:ComponentRef;
private isViewInitialized:boolean = false;
constructor(private resolver: ComponentResolver) {}
updateComponent() {
if(!this.isViewInitialized) {
return;
}
if(this.cmpRef) {
this.cmpRef.destroy();
}
this.resolver.resolveComponent(this.type).then((factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory)
// to access the created instance use
// this.compRef.instance.someProperty = 'someValue';
// this.compRef.instance.someOutput.subscribe(val => doSomething());
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
柱塞示例RC.4
柱塞示例beta.17
更新-使用loadNextToLocation
export class DclWrapper {
@ViewChild('target', {read: ViewContainerRef}) target;
@Input() type;
cmpRef:ComponentRef;
private isViewInitialized:boolean = false;
constructor(private dcl:DynamicComponentLoader) {}
updateComponent() {
// should be executed every time `type` changes but not before `ngAfterViewInit()` was called
// to have `target` initialized
if(!this.isViewInitialized) {
return;
}
if(this.cmpRef) {
this.cmpRef.destroy();
}
this.dcl.loadNextToLocation(this.type, this.target).then((cmpRef) => {
this.cmpRef = cmpRef;
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
Plunker示例beta.17
原版的
从您的问题中不能完全确定您的要求是什么,但是我认为这应该可以满足您的要求。
该Tabs
组件获取传递的类型的数组,并为该数组中的每个项目创建“标签”。
@Component({
selector: 'dcl-wrapper',
template: `<div #target></div>`
})
export class DclWrapper {
constructor(private elRef:ElementRef, private dcl:DynamicComponentLoader) {}
@Input() type;
ngOnChanges() {
if(this.cmpRef) {
this.cmpRef.dispose();
}
this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
this.cmpRef = cmpRef;
});
}
}
@Component({
selector: 'c1',
template: `<h2>c1</h2>`
})
export class C1 {
}
@Component({
selector: 'c2',
template: `<h2>c2</h2>`
})
export class C2 {
}
@Component({
selector: 'c3',
template: `<h2>c3</h2>`
})
export class C3 {
}
@Component({
selector: 'my-tabs',
directives: [DclWrapper],
template: `
<h2>Tabs</h2>
<div *ngFor="let tab of tabs">
<dcl-wrapper [type]="tab"></dcl-wrapper>
</div>
`
})
export class Tabs {
@Input() tabs;
}
@Component({
selector: 'my-app',
directives: [Tabs]
template: `
<h2>Hello {{name}}</h2>
<my-tabs [tabs]="types"></my-tabs>
`
})
export class App {
types = [C3, C1, C2, C3, C3, C1, C1];
}
Plunker示例beta.15(不是基于您的Plunker)
还有一种传递数据的方法,该数据可以传递给动态创建的组件,例如(someData
将需要传递给type
)
this.dcl.loadIntoLocation(this.type, this.elRef, 'target').then((cmpRef) => {
cmpRef.instance.someProperty = someData;
this.cmpRef = cmpRef;
});
还有一些支持将依赖项注入与共享服务一起使用。
有关更多详细信息,请参见https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html