2

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.

enter image description here

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?

1 Answer 1

1

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);
    }  
} 
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.