Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bindings not working in dynamically loaded component

I'm encountering a problem where if I dynamically load a component, none of the bindings in the template are working for me. As well as this the ngOnInit method is never triggered.

loadView() {
    this._dcl.loadAsRoot(Injected, null, this._injector).then(component => {
      console.info('Component loaded');
    })
  }

Dynamically loaded component

import {Component, ElementRef, OnInit} from 'angular2/core'

declare var $:any

@Component({
    selector: 'tester',
    template: `
      <h1>Dynamically loaded component</h1>
        <span>{{title}}</span>
    `
})

export class Injected implements OnInit {

    public title:string = "Some text"

    constructor(){} 

    ngOnInit() {
      console.info('Injected onInit');
    }

}

This is my first time using dynamically loaded components so I think may be attempting to implement it incorrectly.

Here's a plunkr demonstrating the issue. Any help would be appreciated.

like image 707
garethdn Avatar asked Jan 11 '16 18:01

garethdn


1 Answers

As Eric Martinez pointed out this is a known bug related to the use of loadAsRoot. The suggested workaround is to use loadNextToLocation or loadIntoLocation.

For me this was problematic as the component I was trying to dynamically load was a modal dialog from inside a component with fixed css positioning. I also wanted the ability to load the modal from any component and have it injected into the same position in the DOM regardless of what component it was dynamically loaded from.

My solution was to use forwardRef to inject my root AppComponent into the component which wants to dynamically load my modal.

constructor (
    .........
    .........
    private _dcl: DynamicComponentLoader,
    private _injector: Injector,
    @Inject(forwardRef(() => AppComponent)) appComponent) {

    this.appComponent = appComponent;
}

In my AppComponent I have a method which returns the app's ElementRef

@Component({
    selector: 'app',
    template: `
        <router-outlet></router-outlet>
        <div #modalContainer></div>
    `,
    directives: [RouterOutlet]
})

export class AppComponent {

    constructor(public el:ElementRef) {}

    getElementRef():ElementRef {
        return this.el;
    }

}

Back in my other component (the one that I want to dynamically load the modal from) I can now call:

this._dcl.loadIntoLocation(ModalComponent, this.appComponent.getElementRef(), 'modalContainer').then(component => {
    console.log('Component loaded')
})

Perhaps this will help others with similar problems.

like image 62
garethdn Avatar answered Nov 10 '22 19:11

garethdn