Angular Dynamic Components

Or how to escape the never ending *ngIf build up in your Angular4+ templates. Demo included!

Marko Francekovic
Calyx
5 min readOct 16, 2017

--

Every web app I have worked on had the scenario where you have a data set and you need to present each item from that set in a slightly different way.

Usually there is a for loop which goes through the data set and renders that data inside the HTML template. And what tends to happen is that you have a huge template controlled by a lot of IF statements to be able to present each data item in a different way.

This gets very ugly very fast. And before you know it you have something like this — and it keeps growing. You’re adding template variations, classes where you need them, new markup etc.

Angular is providing us with a great solution to this problem called Dynamic Component Loader which uses the ComponentFactoryResolver.

The example — grid view with dynamic components

To showcase this I have created a small Angular app via the Angular CLI. The idea is to have a grid view where every item in the grid would be it’s own component.

Live example / Github code

When thinking about the real world scenario I wanted to achieve the following:

  • avoid *ngIf inside the template
  • have small, reusable templates (in this case components) which would be responsible for presenting the data items in the grid
  • be able to easily add new templates
  • the templates need to render dynamic data

For the example I’m using Bootstrap 4.0.0-beta to style it. It’s not that relevant to the case, but it makes the example look sweet.

Let’s start with the app.component and the data set

In our app.component.ts we define the data set. Each item in the data set has some pieces of information we’ll want to show inside the corresponding grid item. And it holds a key cardType which will be used to define which template to match with the given item.

The app.component.html is pretty straightforward. The only important line there is:

It calls the app-grid component and passes the data to the grid.

Grid component

What we’re saying here is that we want to present an app-grid-item component for each item inside the data set. And we pass the item to the app-grid-item component.

Grid item component

The template of the grid-item component is dead simple. Just a ng-container with an element reference.

This is because we’ll use the ComponentFactoryResolver to dynamically insert our components and render their HTML.

The real magic happens in the GridItemComponent class.

There are few things going on here.

First we have our templateMapper. Which maps the data set item to the appropriate Component.

Then in the ngOnInit we’re using the ComponentFactoryResolver to create the component factory, and we’re using the ViewContainerRef to our ng-container and .createComponent method to instantiate the component from our component factory.

The last step we’re doing is passing the data to the dynamically created component.

You’ll notice that we’re typesetting the component instance to CardTemplateBaseComponent. This is our base component which every other card template component will exted. It has an empty template as it is not intended to be used directly.

Card templates

Each of the components which is to be used inside the grid should extend the CardTemplateBaseComponent class. That way we know each one of them has the data input property.

The components each define their own HTML template and present the data in their unique ways.

In our case we have six Card template components. Here is how one of them looks like:

Important! If you want to have Components dynamically loaded you need to provide them as entryComponents in the Module.

If you don’t do that, the app will not be able to run. But if you’re using Angular CLI to build it is smart enough to warn you of that issue.

Clone the demo app and play around. I for one will surely use this to build cleaner apps, with more reusable templates instead of getting stuck with a ton of *ngIfs and copy pasted code.

If you have some questions or issues in your Angular app feel free to reach me on Twitter — Marko Francekovic.

--

--