Inspired by Angular 2 dynamic tabs with user-click chosen components and Passing Input while creating Angular 2 Component dynamically using ComponentResolver I'm trying to go one step further and have not just the tabs get a dynamic component but also the content of be tab be comprised of dynamic components. From the original example I used components C1-C3 for the tabs and want to use C4 and C5 for sections. I'm aware there isn't any styling/functionality for actually tabbing but the structure should be enough to get me on my way. I made this.
//our root app component
import {Component, ComponentRef, Input, ViewContainerRef, ComponentResolver, ViewChild, Injectable, OnInit} from '@angular/core';
@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.type).then((factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory);
this.cmpRef.instance.info = this.type;
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
@Component({
selector: 'child-dcl-wrapper',
template: `<div #target></div>`
})
export class ChildDclWrapper {
@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.type).then((factory:ComponentFactory<any>) => {
this.cmpRef = this.target.createComponent(factory);
this.cmpRef.instance.info = this.type;
});
}
ngOnChanges() {
this.updateComponent();
}
ngAfterViewInit() {
this.isViewInitialized = true;
this.updateComponent();
}
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
}
@Component({
selector: 'c1',
template: `<h2>c1</h2><p>{{info.name}}</p>
<my-sections [sections]="section"></my-sections>`
})
export class C1 {
}
@Component({
selector: 'c2',
template: `<h2>c2</h2><p>{{info.name}}</p>
<my-sections [sections]="section"></my-sections>`
})
export class C2 {
}
@Component({
selector: 'c3',
template: `<h2>c3</h2><p>{{info.name}}</p>
<my-sections [sections]="section"></my-sections>`
})
export class C3 {
}
@Component({
selector: 'c4',
template: `<h2>c4</h2><p>{{info.name}}</p>`
})
export class C4 {
}
@Component({
selector: 'c5',
template: `<h2>c5</h2><p>{{info.name}}</p>`
})
export class C5 {
}
@Component({
selector: 'my-sections',
directives: [ChildDclWrapper],
template: `
<h3>Sections</h3>
<div *ngFor="let section of type.sections">
<child-dcl-wrapper [type]="section"></child-dcl-wrapper>
</div>
`
})
export class Sections {
@Input() sections;
}
@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;
}
@Injectable()
export class AService {
info = [
{
name: "taco",
type: C1,
sections: [
{
name: "believe",
type: C4
},
{
name: "car",
type: C5
}
]
},
{
name: "pete",
type: C2,
sections: [
{
name: "repeat",
type: C4
},
{
name: "banana",
type: C5
}
]
},
{
name: "carl",
type: C3,
sections: [
{
name: "shotgun",
type: C4
},
{
name: "helmet",
type: C5
}
]
}
];
getServiceInfo() {
console.log("Bung.");
return this.info;
}
}
@Component({
selector: 'my-app',
directives: [Tabs],
providers: [AService],
template: `
<h1>Hello {{name}}</h1>
<my-tabs [tabs]="types"></my-tabs>
`
})
export class App extends OnInit {
types;
aService;
constructor(private aService: AService) {
this.aService = aService;
}
getInfo() {
console.log("beep");
this.types = this.aService.getServiceInfo();
}
ngOnInit() {
console.log("boop");
this.getInfo();
}
}