Angular 2 – Dynamically Injecting Components

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.

4 comments

  1. hi.. very helpful post.. but i have another use case where my template with #dynamicTarget is generated dynamically.. in that case when i use @viewChild.. i am not getting anything in the ViewContainerRef because its not yet generated. how can i fix this please help me

    1. It really depends on how the container is being generated, when and by what. Without that kind of information giving you a solution is pretty tricky. Best bet would be to post up your specific source code examples on Stack Overflow and see what solutions are available.

      1. i already posted in stackoverflow. till now no one had replied.

        http://stackoverflow.com/questions/40148345/loading-component-to-dynamically-generated-templates

        instead of writing template like below

        @Component({
        selector: ‘home’,
        template: ”
        })
        i use a html file to load the html snippet.. but in that that many template tags will be generated using jquery with different anchor.

        and i would like to know how to create the following code dynamically because there will be n number of templates with ids i cannot hardcode it.

        @ViewChild(‘component1’, { read: ViewContainerRef }) Component1: ViewContainerRef;

        Please help

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s