实例化的组件然后将其自身注册为新的选项卡。
我不知道这是否是“最好的”方法? Sofar我看到的唯一指南是静态选项卡,这没有什么帮助。
到目前为止,我只有标签服务,这是bootstrap在主要持久整个应用程序,看起来像这样的东西。
export interface ITab { title: string; } @Injectable() export class TabsService { private tabs = new Set<ITab>(); addTab(title: string): ITab { let tab: ITab = { title }; this.tabs.add(tab); return tab; } removeTab(tab: ITab) { this.tabs.delete(tab); } }
问题:
1)如何在收件箱中创建一个动态列表,创建新的(不同的)选项卡?我有点猜测DynamicComponentBuilder将被使用?
2)如何从收件箱创建的组件(点击)注册自己的标签,并显示?我猜ng-content,但我找不到如何使用它的很多信息
编辑:尝试澄清
将收件箱视为邮件收件箱,项目将作为JSON获取并显示几个项目。单击其中一个项目后,将创建一个带有该项目操作“type”的新选项卡。类型是一个组件
编辑2:图像
ngComponentOutlet已添加到4.0.0-beta.3
更新
有一个NgComponentOutlet工作正在进行,类似于https://github.com/angular/angular/pull/11235
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,C1]; }
@NgModule({ imports: [ BrowserModule ],declarations: [ App,DclWrapper,Tabs,C3],entryComponents: [C1,bootstrap: [ App ] }) export class AppModule {}
旧版本xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
这在Angular2 RC.5中再次改变
我将更新下面的例子,但它是度假前的最后一天。
这个Plunker example演示了如何在RC.5中动态创建组件
更新 – 使用ViewContainerRef.createComponent()
因为不推荐使用DynamicComponentLoader,所以该方法需要重新更新。
@Component({ selector: 'dcl-wrapper',{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(); } } }
Plunker example RC.4
Plunker example 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(); } } }
原版的
不完全确定从你的问题你的要求是什么,但我认为这应该做你想要的。
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]; }
@L_403_8@(不是基于你的Plunker)
还有一种方法来传递数据,可以传递到动态创建的组件像(someData将需要像类型传递)
this.dcl.loadIntoLocation(this.type,'target').then((cmpRef) => { cmpRef.instance.someProperty = someData; this.cmpRef = cmpRef; });
还有一些支持使用共享服务来使用依赖注入。
详情请参阅https://angular.io/docs/js/latest/api/core/DynamicComponentLoader-class.html