Update 2022, Angular v14 but applicable to lower versions as well.
@LeonardoRick solution is very proper.
Nevertheless, there is another solution, more adequate to Angular docs official example for dynamic component loader (link to docs).
So, there is proposal to make a usage of directive
, which has defined viewContainerRef
.
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[adHost]',
})
export class AdDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}
This directive in a component is defined with ViewChild
:
@ViewChild(AdDirective, {static: true}) adHost!: AdDirective;
So, how to apply above solution to asked question and render multiple dynamic components?
Solution:
Directive keeps the same. However in component, instead of using ViewChild
there will used ViewChildren
and QueryList
as above:
@ViewChildren(AdComponentDirective) _adComponentDirective: QueryList<AdComponentDirective>;
Due to usage of QueryList
there must be applied also ngAfterViewInit
lifecycle hook cuz right then the QueryList
is ready and loaded. Have a closer look at populateViewContainersWithComponents
method, in which is dynamic components assignment to tabs.
export class AdminTabsComponent implements AfterViewInit {
@ViewChildren(AdComponentDirective) adComponentDirective!: QueryList<AdComponentDirective>;
@Input() tabsInfo: TabsInfoModel;
constructor(private cdr: ChangeDetectorRef) {}
ngAfterViewInit(): void {
this.populateViewContainersWithComponents();
}
private populateViewContainersWithComponents(): void {
this._dynamicComponentDirective.toArray().forEach((container, index) => {
container.viewContainerRef.createComponent(this.tabs[index].component);
});
this.cdr.detectChanges();
}
}
In the template:
<mat-tab-group>
<mat-tab *ngFor="let item of tabs; index as i" label="{{ item.label }}">
<ng-template adHost></ng-template>
</mat-tab>
</mat-tab-group>