3 Steps to Creating Dynamic Views in Angular

Dynamically loading components without directives

Zeng Hou Lim
Nov 30, 2019 · 6 min read
Photo by Émile Perron on Unsplash


Often times, we need to render a child view dynamically. For instance, we might have a parent view that has a tab menu, and we’d like to render the views in accordance with whichever tab is being selected.

Being new to Angular, this is something I experience, and it took me a fair amount of time to get the implementation working despite following the official Angular guide. Reading Maxim Koretskyi’s article on DOM manipulation definitely helped my understanding, so I’ll recommend you give it a read, too, if you want more in-depth explanations.

In this piece, I’ll highlight and summarize three key concepts that’ll quickly get you running.

1. Creating the View

Before we can insert a view, we first have to know how to create one. Angular supports two types of views, namely host views and embedded views.

Host views

This is the view we use most frequently and are probably most familiar with. When Angular creates a component, we get a view that also contains the data of the component. When we talk about host views, they’re essentially the instantiated component views.

To create a component, we simply include its selector in the template of another component, and Angular automatically does the rest. However, when we are dynamically creating views, there are two intermediary steps necessary.

We need a ComponentFactory, which will be used to manually (i.e. dynamically) create a component. In order to get a ComponentFactory, we need to to use the ComponentFactoryResolver by passing in the component as a parameter.

Let’s say we wish to create a dynamic component upon initialization:

<-- parentComponent.component.ts -->import { ..., ComponentFactoryResolver } from '@angular/core';
import { FirstComponent } from '<path>/firstcomponent.component.ts'
...export class ParentComponent implements OnInit {constructor(private resolver: ComponentFactoryResolver) {}
ngOnInit() {
const componentFactory = this.resolver.resolveComponentFactory(
const dynamicallyCreatedComponent = componentFactory.create();

Important: You need to define the component in NgModules’s entryComponents within the app.module.ts file. In the Angular doc’s dynamic-component loading section, this portion wasn’t included, and it took me a while to figure it out.

<-- app.module.ts -->
providers: [],
bootstrap: [AppComponent],
entryComponents: [FirstComponent]

“An entry component is any component that Angular loads imperatively (which means you’re not referencing it in the template) by type.” — Angular.io

Embedded views

<-- parentComponent.component.html -->
<div>This is rendered</div>
<ng-template #templateName>
<div> This is not rendered</div>

ATemplateRef is a blueprint for creating DOM elements, just like how a class is to an instance of itself. When you reference a ng-template, you get a TemplateRef. If you include a ng-template in your component.html file, it’ll not be rendered since you need to be initialize the view and embed it after. In the following section, we’ll talk about how to to reference a DOM element.

For now, we simply need to know we’re able to select the ng-template via its selector name, #templateName, and that we’re able to create an instance of it — which is what we call the embedded view.

If you are interested, you can read more about the difference between host and embedded views.

2. Selecting the DOM Element

If you want to dynamically render a view, you can imagine there’s an element that serves as an anchor point to tell Angular where the view should be inserted. If you had experience with jQuery, it would be similar to:

<div id="selector></div> // HTML$('.selector').html('Dynamic Content Here') // jQuery selector

In Angular, we use the decorators @ViewChild and @ViewChildren to search for the element(s). They both provide similar functionality, but the former returns only a single reference. The latter returns a QueryList object that has multiple references to elements.


@ViewChild(selector, [{read: any}], [{static: boolean}])

A little more explanation on the metadata properties here: read and static are both optional parameters, but I’ll quickly talk about them.

In Angular’s documentation, it says that read should be set to “true to read a different token from the queried elements.” However, a more practical usage would be to include the class of the element you’re interested in.

In this Stack Overflow post, it says there can be several instances tied to the element selector. For instance, for each element, there are at least an ElementRef and a ViewContainerRef. Don’t worry if these two classes sound foreign to you now, I’ll touch on the latter in just a bit.

The Static property is more straightforward. Set it to true if you want the query results to run before the change detection occurs.

Let’s look at an example to see how we can get access to the ViewContainerRef of the element.


<-- parentComponent.component.html --><div>
<ng-container #viewContainer></ng-container>
<-- parentComponent.component.ts -->export class ParentComponent implements OnInit {
@ViewChild('viewContainer', read: ViewContainerRef) viewContainer: ViewContainerRef;

3. Attaching the View

Now that we’re able to selector an anchor element, we need to attach view(s) to it. The ViewContainerRef represents the container of the element that we can attach views after.

Anchor elements

In the above example, we’re using ng-container as the anchor element. Alternatively, we can also use the ng-template. I suspect some folks would be curious as to whether or not we can use other elements, such as a div. Theoretically, we can use any elements we want.

However, it’s important to note that Angular doesn’t actually insert views in the element, but rather after the element bounded to the ViewContainer.

Both ng-container and ng-template don’t actually get rendered in the DOM but, rather, as comments that Angular knows to find. As such, using these elements allows us to avoid inserting excessive elements into the DOM, such as an unwanted div.

Inserting the view

In the above code block, we already have an instance property called viewContainer, and we simply have to inject the view.

<-- parentComponent.component.ts -->import { ..., ComponentFactoryResolver } from '@angular/core';
import { FirstComponent } from '.../firstcomponent.component.ts';
import { SecondComponent } from '.../secondcomponent.component.ts';
...export class ParentComponent implements OnInit {
@ViewChild('viewContainer', read: ViewContainerRef) viewContainer: ViewContainerRef;
constructor(private resolver: ComponentFactoryResolver) {}
...onTabChange(selectedTab) {
this.viewContainer.clear(); // clear all views
if (selectedTab === 'firstComponent') {
const componentFactory = this.resolver.resolveComponentFactory(
} else if (selectedTab === 'secondComponent') {
// similar idea here

Earlier, we used the .create() method from the ComponentFactory object, but the ViewContainerRef has a method that takes in a ComponentFactory, creates the host view by internally calling its create function, and inserts the view automatically.

Passing data to the dynamic component

Right now, we have the ability to dynamically create host views. One useful thing to be able to do is to also pass in data to our component. That way, we are able to dynamically create host views with dynamic data.

Let’s build on the above example.

<-- parentComponent.component.ts -->const componentRef =
(componentRef.instance).dynamicData = { a: 5, b: 3}; // passing data
<-- firstComponent.component.html -->
<div> Dynamic Content: {{ dynamicData.a }} </div>

The createComponent method returns a ComponentRef object, which we can use to access the instance property and add a dynamicData key. That way, in our child component, we can simply reference the data variable name via interpolation.

Creating an embedded view

Now that we know how to create a host view, embedded views are almost similar conceptually. Recall that we talked about TemplateRef earlier? We can essentially create an embedded view with that.

<-- parentComponent.component.html --><div>
<ng-container #viewContainer></ng-container>
<ng-template #isLoggedInTemplate>
<div> You are logged in! </div>
<-- parentComponent.component.ts -->export class ParentComponent implements OnInit {
@ViewChild('viewContainer', read: ViewContainerRef) viewContainer: ViewContainerRef;
@ViewChild('isLoggedInTemplate', read: TemplateRef) template:
...displayLoginMessage() {

We simply add another TemplateRef instance property and use the ViewContainer’s method to instantiate the view and insert it.

Final Words

By understanding these threeconcepts, you should be able to create dynamic views in Angular easily.

In the official guide, the dynamic component loading is implemented sightly differently with the help of directives. I decided to talk a little more about doing it without since it seems to save the hassle of creating a directive. Nonetheless, it would be good to also look at the official docs to understand the underlying mechanisms.

Better Programming

Advice for programmers.

Zeng Hou Lim

Written by

Software Engineer at LeanData. Excited about living my best life and becoming a better engineer. I like taking complex ideas and breaking them down.

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade