August 17, 2016

Dynamically Render Components with ComponentFactoryResolver in Angular 2

In my current project I came to a situation where it was necessary to drop specific components into my view. Since the project is a game and the current view should not be tied to URLs at this point i decided not to use the router but to load my various components dynamically into my view. This gives me the power to handle the logic in one persistent smart component which is bound to a URL.

My project was build with Ionic 2 and Angular, but i’ll go with plain Anuglar 2 for this blog post. The equivalent approach in Angular 1 would have used the $compile service. In Angular 2 there was a very simple approach using the ComponentResolver but the class is deprecated and will be removed from Angular 2. This blog post will guide you how to use the ComponentFactoryResolver together with NgModule in order to render Angular 2 components dynamically. This approach is only eligible for components that already exist in your application and not for components that will be received trough API calls for example. To live render external compontents take a look in this Stackoverflow question.

First of all lets create a fresh Angular 2 RC5 project.  Make sure to have the angular-cli webpack beta installed to create a new project with RC5.

Then create the new project:

And launch the project with:

Now you are all set, lets get started with the actual code! This empty setup provides us with an AppComponent that will act as our host component in which we want to render several child components. So lets create the child components first.

Instead of calling the components in our HTML code we want to inject them via JavaScript when needed. Since we have no logic lets just go with a setTimeout as initiator of the component rendering. Add this dummy code to your app components constructor:

Now add a DIV to the AppComponent which will hold our child components:

Capture the #parent element in your TypeScript code as follows:

To get the components we use the ComponentFactoryResolver, inject it into the constructor and declare 2 variables which will receive our components:

Now we are ready to inject the childComponent and the anotherChildComponent into our view. To do so call the createComponent method on the parent object.

The last required step is to list the components as entryComponents either in your app.components.ts @Component({}) decorator or in the app.modules.ts:

 

This should lead to the following result:

ng2

In a real world application you probably want to remove the dynamically rendered components at some point. In order to do so it is required to store the return of this.parent.createComponent() in a variable. Lets add another setTimeout and remove the another child component after another 500 milliseconds.

Thats it! If you have any questions feel free to use the comment section.

Related Posts

Avatar photo

theCodeCampus
Developer at thecodecampus </>

Our knowledge is not simply gained through reading - it is trained, tested and constantly being expanded. Because first and foremost, we are all developers at W11K. The know-how that we acquire here as developers, consultants and information architects flows immediately into our training courses and articles for theCodeCampus.


37 responses to “Dynamically Render Components with ComponentFactoryResolver in Angular 2”

  1. Gilles P says:

    Thanks for the example, it saved me a lot of investigation time! Do you know if the same approach is also compatible with Angular 2 RC6?

  2. Abner says:

    Would you be able to provide final release Example? Trying to find a way to load existing components dynamically,, but I cant find.

  3. Can Kattwinkel says:

    Hello Abner,

    the full code is above. Just kickstart a new ng2 project with angular cli and then paste in the snippets from above.

    If you receive any error, I’m happy to help.

  4. Namek says:

    I moved my component creation to service and couldn’t move forward. I didn’t know that entryComponents exists not only in @Component but also in @NgModule. Thanks!

  5. Damir says:

    Hello,

    can this be applied to content gotten from an API call?

    I am getting for example this

    this.pageContent = ”
    Some title
    Lorem ipsum text”

    right now I am doing in my view:

    Obviously “page-component-test” component is not getting transcluded

    How do I do that on the fly? (or after I get the response from the API)

    • Peter says:

      I have found this solution to load component into DOM element without using ViewContainer:

      import {Component, ComponentFactoryResolver, Injector, ApplicationRef} from ‘@angular/core’;
      import {ChildComponent} from “./child/child.component”;

      @Component({
      selector: ‘app-root’,
      template: ”
      })
      export class AppComponent {
      constructor (private componentFactoryResolver: ComponentFactoryResolver, private injector: Injector, private appRef: ApplicationRef) {
      }
      createChildComponent() {
      const childComponent = this.componentFactoryResolver.resolveComponentFactory(ChildComponent);
      var childComponentRef = childComponent.create(this.injector, null, ‘#parent’);
      (this.appRef)._loadComponent(childComponentRef);
      }
      }

      • Prateek says:

        ‘_loadComponent’ does not exist on type ‘ApplicationRef’

        • webdev says:

          Hi Prateek ,

          Are you able to get any solution for transcluding the child selectors that are in a string and display them on view? Thanks!!

  6. Damir says:

    eh, the HTML is not showing in the comment
    https://jsfiddle.net/pbre3rbk/ <- here

    • webdev says:

      Hey Damir ,

      Are you able to figure out any solution for this ? I’m facing the same issue and need some solution for it.Thanks!!

  7. Jay says:

    Excellent article, thank you for documenting – I have one question, how would you go about passing inputs into the child components?

  8. Dave says:

    @Jay: Working from the last example above where you store the return of the CreateComponent method, you can access properties on the child component via the instance property: anotherChildComponentHolder.instance.myProp = “myVal”; You can also call functions on the created component the same way: anotherChildComponentHolder.instance.myFunc(“hello world”);

    HTH.

  9. Renne says:

    Thanks for taking the time to write this out, it helped a lot!

  10. Marco QU says:

    Is there any way to render components which be received from server?

    • Can Kattwinkel says:

      Probably, take a look at Angular Universal, Ahead of Time Compiling and Lazyloading. But in general you should send data from your server – not components.

  11. Aman says:

    Is it possible to pass some data like object or array to child component?

    • Can Kattwinkel says:

      Yes for sure.

      When you create a component, you get the ComponentRef in return. Calling the “instance” gives you full access to the class of ChildComponent

      this.parent.createComponent(childComponent).instance.someMethodOnChildComponent

  12. Dareq says:

    Hi,

    Is it a safe solution ? Is it possible that someone replace the component code loaded dynamically ?

    Best regards

    • Can Kattwinkel says:

      Yes this should be safe. Since this approach doesn’t dynamically loads the component. This would be bad practice (at least in my opinion). You should load dynamic data not dynamic templates. The component is served with the client. Also it is listed in the entryComponents. So Ahead of Time Compiling should work out of the box.

      • Dareq says:

        Thank you. You are right, it is not loaded dynamical, it is render dynamical. Thank you for sharing this solution.

  13. Bailey says:

    Thank you for your effort.

  14. Serak Shiferaw says:

    zero help from angular 2 guys, i why need to import anotherchildcomponent() if it is dynamic image using it in an enterprise application where you have thousends of components that load on demand.

    from this example i can tell i will write them all inside entrypointcomponent and also have to import thousands of components

  15. geordie says:

    when inspecting the components, it appears to load them below the div, not within

    • Can Kattwinkel says:

      I’d recommend you to take a look at NgComponentOutlet. Its a new feature of Angular 4.

  16. Sosolen says:

    Thanks alot!

    really clear and helpful !

  17. Benedikt says:

    Why is the code just running inside the setTimeout() functions? If I try to run this.parent.createComponent() directly under const anotherChildComponent = this.componentFactoryResover.resolveComponentFactory() I get an error “error_handler.js:54 EXCEPTION: Cannot read property ‘createComponent’ of undefined”. How can I run the tasks without timeout functions?

    • Can Kattwinkel says:

      Because the parent component (div#parent) is not yet loaded. This was just an example, if you want to do it on Component initialization then the constructor is the wrong place.

      Move your code to the OnInit Lifecycle Hook and it will work.

  18. Harish says:

    Can we pass parameters to child component?

  19. Razvan says:

    I am not a fan of the setTimeout(), maybe move the code to ngOnInit()

  20. Samuel says:

    Just curious….how would we add …. to . I can see in my inspector it adds ….

    in the tbody as wanted but the display is incorrect. If i edit the html in the inspect and remove it works great.

    How can I correctly insert the …. in my child element in the tbody of the parent component?

  21. Sammy says:

    Hi,

    Thanks very much. It works well. Just one question: In my child component, I have a text box and a button. On click of the button, I want to send the data entered in the texbox and “emit” it back to the parent. For that I tried:

    parent:

    global_data:any[]=[];

    let instance:any=this.stockin_items_containair.createComponent(this.stockItemFormComponent);
    instance.instance.eventActionHandler.subscribe(this.emittedNewRowAction)

    emittedNewRowAction($event){
    //$event contains data sent from child so save it now
    console.log($event); // ===================>CORRECT. I see data emitted
    this.global_data.push({‘id’:$event}); ==> tihs.global_data is undefined.
    }

    child:

    @Output() eventActionHandler=new EventEmitter();//

    sendValueToParent(){

    this.eventActionHandler.emit(data);

    }

  22. muneera says:

    How to render child components withoutusing setTimeout function ? May be on a button click

  23. Troy Harris says:

    Might be good to note an update to the @ViewChild decorator, as after Angular version 8 (optional?) or 9 (required?) there is an additional attribute “static” that needs to be added and set to true or false:

    @ViewChild('parent', { read: ViewContainerRef, static: false })

    See https://angular.io/guide/static-query-migration

  24. joker123 says:

    Hello, always i used to check web site posts here early in the dawn, as i love to gain knowledge of more and more.

  25. Edoardo says:

    Thanks a lot! But what if I want to render also the sub-components of a dynamic component?

  26. Nath says:

    Hi,

    My child element have a property that I’d like to pass when I create it.
    I’ve tried multiple things, it didn’t work.

    Can you tell me what I should add here ?
    Cellcomponent is the child and I would like to add an id inside.


    const childComponent = this.componentFactoryResolver.resolveComponentFactory(CellComponent);
    // here should be added the id
    this.parent.createComponent(childComponent);

Leave a Reply

Add code to your comment in Markdown syntax.
Like this:
`inline example`

```
code block
example
```

Your email address will not be published.