Angular 2 – Dynamically Injecting Components

Datetime:2016-08-23 02:34:10          Topic: AngularJS           Share

Note this also covers upgrading from RC4 to RC5’s ComponentFactoryResolver.

I recently upgraded from RC4 to RC5 and as a result my dynamic component injection module failed due to ComponentResolver being deprecated. Of all the changes between RC4 and RC5, this seems to be the simplest deprecation step, but though I’d document it here.

Generating and Injecting Components

To dynamically inject componets, we need to use ComponentFactoryResolver to create both the factory and the component, as opposed to ComponentResolver and ComponentFactory in RC4.

// These will be your basic imports for component injection
import {Component, ViewContainerRef, ComponentFactoryResolver, ViewChild} from '@angular/core';

ComponentFactoryResolver now does all of the work, which needs to be injected into the componet that will be responsible for doing the injection.

Previously you would have injected a ComponentResolver.

constructor(private resolver: ComponentFactoryResolver) {
}

You then need to identify where in your HTML code the component needs to be injected. You do this by using ViewContainerRef to pull out the element where you want the component to drop.

@Component({
    ...
    template: '<div #dynamicTarget></div>',
    ...
})
export class InjectedWrapperComponent {

    // Component input
    @ViewChild('dynamicTarget', { read: ViewContainerRef })
    private dynamicTarget: any;

    ...
}

Injecting the component is then as simple as creating a ComponentFactory<> using resolveComponentFactory and using that to create a new component in place of the ViewContainerRef.

let componentFactory = this.resolver.resolveComponentFactory(MyDynamicComponent);
this.dynamicTarget.createComponent(componentFactory);

You’ll now have your component beind rendered correctly within your component view.

Sort of, if you’ve put the ‘resolveComponentFactory’ code in the right place.

Injection and Life Cycle Hooks

You’ll need to hook into your components life cycle to correctly create and destroy your injected component – specifically ngOnInit and ngOnDestroy (in RC4 it was OK to use ngAfterViewInit rather than ngOnInit but this is no longer possible).

// We have a few more imports now
import {Component, ComponentRef, ViewContainerRef, ComponentFactoryResolver,
        ViewChild, OnInit, OnDestroy} from '@angular/core';

...

export class InjectedWrapperComponent implements, OnInit, OnDestroy {

    // We'll need to keep track of our injected component to manage it correctly
    private componentReference: ComponentRef;

    ngOnInit() {
        // Create our component now we're initialised
        let componentFactory = this.resolver.resolveComponentFactory(MyDynamicComponent);
        this.componentReference = this.dynamicTarget.createComponent(componentFactory);
    }

    ngOnDestroy() {
        // If we have a component, make sure we destroy it when we lose our owner
        if (this.componentReference) {
            this.componentReference.destroy();
    }
}

And that’s it, you have a component being injected and being rendered within our owners view.

Example Code

The code for the above is available on GitHub, and includes the diff when converting from RC4 to RC5. The GitHub code also shows how to change your dynamically injected component on the fly using ngOnChange to destroy the existing one and inject a new one on demand.





About List