I want to create some dynamic components inside another component, but not just once, many times. And that number is also dynamic.
So I was using ComponentFactoryResolver to create the component and then ViewChild to inject that component dynamically. The problem, as I said, is that I need to do that in many places, so I'd need to use ViewChildren to retrieve all references and inject the component (with a certain input data).
I've a plunker where I reduced the problem to what I need. I have a component which is passed an array of data and the type of the component to create.
@Component({
selector: 'my-app',
template: `
<div>
<my-parent [data]="rows" [inner]="component">
</my-parent>
</div>
`
})
export class AppComponent {
rows = [
{ name: 'data1' },
{ name: 'data2' },
{ name: 'data3' },
{ name: 'data4' }
];
component = ChildComponent;
}
In my-parent, I display a table with one row for each element in the data received as parameter, but also, I want to display below each row, another row with a component of the type also passed as parameter.
As an example, above all rows I'm doing this exact thing for one component, where I'm passing name='TOTAL'. So I use an <ng-container #entry>
to retrieve the reference and inject the component.
I try to the same for the dynamic refs and it does not work. I created a directive Host so that I can retrieve it with ViewChildren with an specific id, but then when I try to create the component dynamically, it does not work.
This is the code
@Directive({
selector: 'host'
})
export class Host {
@Input() id: string;
}
@Component({
selector: 'my-parent',
template: `
<table>
<thead>
<tr>
<th>my data header</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<ng-container #entry></ng-container>
</td>
</tr>
<ng-container *ngFor="let d of data; let i = index;">
<tr>
<td>{{ d.name }}</td>
</tr>
<tr>
<td>
<host id="{{i}}"></host>
</td>
</tr>
</ng-container>
</tbody>
</table>
`
})
export class ParentComponent implements OnInit, AfterContentInit {
@Input() data: any;
@Input() inner: any;
@ViewChildren(Host) hosts: QueryList<Host>;
@ViewChild('entry', { read: ViewContainerRef }) entry: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) {}
ngOnInit() {
}
ngAfterViewInit() {
if (this.hosts) {
const componentFactory = this.resolver.resolveComponentFactory(this.inner);
this.hosts.forEach(host => {
console.log(host);
const component = host.createComponent(componentFactory);
component.instance.name = host.id;
});
}
}
ngAfterContentInit() {
const componentFactory = this.resolver.resolveComponentFactory(this.inner);
const component = this.entry.createComponent(componentFactory);
component.instance.name = 'TOTAL';
}
}
And here is the plunker
It seems the hosts elements that I retrieve can´t injected upon. Any ideas to fix it?
Thanks.
Inject ViewContainerRef
into host directive :
@Directive({
selector: 'host'
})
export class Host {
constructor(private viewRef: ViewContainerRef) {}
@Input() id: string;
}
and after that do host.viewRef.createComponent(componentFactory)
ngAfterViewInit() {
if (this.hosts) {
const componentFactory = this.resolver.resolveComponentFactory(this.inner);
this.hosts.forEach(host => {
console.log(host);
const component = host.viewRef.createComponent(componentFactory);
component.instance.name = host.id;
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With