Loading Components Dynamically in Angular

Shilpa Lalwani
Angular In Depth
Published in
5 min readMay 6, 2020
Icon Courtesy: Cloud component by ProSymbols from the Noun Project

Dynamic Components in any framework/library make building large-scale apps way easier.

Imagine we have a huge module that consists of multiple components. Every user has unique needs, meaning that they will only use a subset of all the available components.

So it doesn’t make sense to load the whole module for every user, right? The components should be loaded on demand, only if they’re used. The goal of this article is to do exactly that.

To make things easier, let’s consider a use-case. We have an application with role-based user access. Each type of user has a different profile page and can perform different actions based on their type.

The Problem

Now how do we show a different Component for a different type of user?

One thing that we can do is use the ngIf structural directive to conditionally show a specific Component based on the user type.

But this would still require us to download both the component for every type of user. That does not make any sense, right?

Solution

How about loading the required Component dynamically, on-demand?

That way we won’t bloat up the main bundle with both these components and will only download the component that should be rendered for a particular user. I’m sure if you have bundle-phobia, you’d definitely wanna do that 😉.

How? 🤔

Before we start implementing dynamic components in Angular, let’s first understand what they actually are.

The dynamic component is one of the core concepts introduced in Angular. The dynamic component is the component that is created dynamically at the runtime. Angular has its API for loading components dynamically.

Difference between 2 apporaches
Difference between the above two approaches (Source — unknown)

Let’s take a look at how we can build dynamic components in Angular. To implement dynamic component loading in our Angular App, we’ll need:

  • Components that need to be loaded dynamically.
  • Service to load and resolve the Component dynamically.
  • Directive to handle viewContainerRef.

Tl;DR:

  • Create Guest Card and User Card Component
  • Implementing Service to Load and Resolve Component
  • Creating Profile directive and Profile component
  • The final step, Updating App component and App module🤓
  • Final words 🧡

Implementation 👩🏻‍💻

It’s time to have fun. Let’s start with the following steps:

  • Open cmd & Run the command ng new dynamic-component
  • Open the new project in your editor of choice.

Or if you just wanna follow along, start with this Sample StackBlitz.

Let’s start coding 💪

1. Create Guest Card and User Card Component

As we totally see from the image above, we need two Components, a card for the normal guest profile and one for the registered user.

Let’s create 2 new Components GuestCardComponent & UserCardComponent ClientProfileComponent as following:

First, we will create GuestCardComponent.It’s just a simple Card that shows the user some information about the App and temps them to sign-in for more features.

Now let's create UserCardComponent It’s just a simple card that shows the information about the user profile.

2. Implementing Service to Load and Resolve Component

In the service, we will implement a method to load and resolve components according to the given state.

In this service, we will start by creating a Subject to manage the isLoggedIn state, and two methods login and logout to pass events into the subject.

And finally, a magical method🎩

loadComponent method takes a ViewContainerRef and the isLoggedIn state. In order to get a reference to our template element in the my-app component we will use ViewContainerRef.

ViewContainerRef :

As the name suggests, its a reference to a container. ViewContainerRef stores a reference to the template element (our container that would host the dynamically loaded component ) and also exposes an API to create components.

Before we proceed to the createComponent() method from ViewContainerRef, we need to add one more service.

The ComponentFactoryResolver service exposes one primary method, resolveComponentFactory.

The resolveComponentFactory() method takes a component and returns a ComponentFactory.

We can think of ComponentFactory as an object that knows how to create a component.

And finally, we will just put everything together inside loadComponent method.

In this method first, we will Clear the ViewContainerRef. In order to create the component we need to remove the previous view every time, otherwise, it will append more components to the container.

Once ViewContainerRef is cleared we will add a condition to get component according to isLoggedIn status, after that we will pass the component toresolveComponentFactory() method.

After that, we are calling the createComponent() method. Internally this method will call the create() method from the factory and will append the component as a sibling to our container.

3. Creating Profile directive and Profile component

In order to make the loading of the components easier, we will create a directive that will inject ViewContainerRef to access the view container of the element that host the dynamic added component.

Let’s create a file src/app/profile/profile-host.directive.ts:

profile-host.directive.ts

This is just a trick to make it easier to get the ViewContainerRef we’re looking for.

Now let’s create ProfileComponent. We will be creating a simple ng-template.

The <ng-template> element is a good choice for dynamic component because it doesn’t render any additional output. we will attach the ProfileHostDirective inside the template, so we can use the ViewChild decorator, and get the viewContainerRef.

In OnInit method, we are getting the viewContainerRef, and using the isLoggedIn$ observable from ProfileService to know every time the isLoggedIn state changes. Then, using the mergeMap operator, we call the loadComponent function that is doing the real magic.

profile.component.ts

4. The final step, Updating App component and App module🤓

Now since we have implemented our services and components let’s update the AppComponent and AppModule.

We will include our ProfileComponent in AppComponent template

Now, the only thing we cannot forget to do is add ProfileComponent, and ProfileHostDirective to the AppModule declarations array, let’s do it

— For Ivy disabled Applications —

If Ivy is disabled in the application, for dynamically loaded component and a ComponentFactory to be generated, the component must also be added to the module’s entryComponents as following:

declarations: [
AppComponent,
GuestProfileComponent,
ClientProfileComponent
],
entryComponents: [GuestProfileComponent,ClientProfileComponent],

According to the definition of entryComponents

Specifies a list of components that should be compiled when this module is defined. For each component listed here, Angular will create a ComponentFactory and store it in the ComponentFactoryResolver.

And It’s done ✅ . Our application is ready to load components dynamically.

The source code is available on GitHub. Also, find the code for Ivy disabled application here.

Final words 🧡

I hope that you had as much fun coding this as I did while writing this code. Now you know how to dynamically load components with lazy loading. With this knowledge, we can reduce the main bundle size, and make the experience better for users.

Thanks for reading! 👍

--

--