Reputation: 4987
As the title says, I'm trying to create a component dynamically, inside a component that was also dynamically created.
I've got this class here
export class DefaultLayoutComponent {
constructor(private cdRef: ChangeDetectorRef, public defaultLayoutService: DefaultLayoutService,
private resolver: ComponentFactoryResolver) {
}
@ViewChild("appAsideContainer", { read: ViewContainerRef }) appAsideContainer: ViewContainerRef;
ngOnInit() {
//other component can call a method on the service, to control the layout...
this.defaultLayoutService.e_openAppAside.subscribe(params => {
let appAsideRef;
//if there are no component inside it already, create one at least
if (this.appAsideContainer.length == 0) {
const appAsideFactory =
this.resolver.resolveComponentFactory(CustomAppAsideComponent);
appAsideRef = this.appAsideContainer.createComponent(appAsideFactory);
}
let appAsideComponent = <CustomAppAsideComponent>appAsideRef.instance;
//create comp. dynamically
const factory = this.resolver.resolveComponentFactory(params.type);
let component = appAsideComponent.container.createComponent(factory);
//append all input values to components
if (params.inputs) {
for (let p in params.inputs) {
component.instance[p] = params.inputs[p];
}
});
}
}
The issue is that members of appAsideComponent
aren't accessible. It doesn't seem to be fully instantiated.
CustomAppAsideComponent in question is here
export class CustomAppAsideComponent {
/** custom-app-aside ctor */
constructor() {
}
@ViewChild("container", { read: ViewContainerRef }) public container: ViewContainerRef;
}
And its markup:
<app-aside [fixed]="true" [display]="false">
<ng-template style="border: solid 2px;" #container></ng-template>
</app-aside>
app-aside
is a component that generates a sidebar that opens vertically to the right.
I can usually create other components with no problem using this method, but it fails on this one. Both AppAsideComponent
and CustomAppAsideComponent
are in my module's entryComponent
Anything obvious I'm missing?
Upvotes: 2
Views: 1632
Reputation: 1536
For this problem you have to create a ngAfterViewInit life cycle hook in the initially created dynamic component and if you dynamically create the first dynamic component you have the dynamic components native element on that you have to create second dynamic component.
<!-- app.component.html -->
<p>Page1</p>
<ng-container #sample1></ng-container>
/* app.component.ts */
import {
Component,
Input,
OnInit,
ViewChild,
ComponentFactoryResolver,
OnDestroy,
ViewContainerRef
} from '@angular/core';
import {
Page1Component
} from './page1/page1.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'dynamicloader';
@ViewChild('sample1', {
read: ViewContainerRef,
static: false
}) sample: ViewContainerRef;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
ngOnInit() {
this.sample.clear();
let page1ComponentFactory =
this.componentFactoryResolver.resolveComponentFactory(Page1Component);
let page1ComponentRef = this.sample.createComponent(page1ComponentFactory);
}
}
<!-- page1.component.html -->
<p>Page2</p>
<ng-container #sample2></ng-container>
/* page1.component.ts */
import {
Component,
Input,
OnInit,
ViewChild,
ComponentFactoryResolver,
OnDestroy,
ViewContainerRef,
AfterViewInit
} from '@angular/core';
import {
Page2Component
} from './page2/page2.component';
@Component({
selector: 'app-page1',
templateUrl: './page1.component.html',
styleUrls: ['./page1.component.scss']
})
export class Page1Component implements AfterViewInit {
@ViewChild('sample2', {
read: ViewContainerRef,
static: false
}) sample2: ViewContainerRef;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
ngAfterViewInit() {
this.sample2.clear();
let page2ComponentFactory =
this.componentFactoryResolver.resolveComponentFactory(Page2Component);
let page2ComponentRef = this.sample2.createComponent(page2ComponentFactory);
}
}
Upvotes: 1