Dynamic Components in Angular 16

Find out if the Angular v13 update actually simplified dynamic component creation.

Kamil Konopka
Bits and Pieces

--

Photo by Max Duzij on Unsplash

With the Angular v13 release, the revamped concept of dynamic component usage was introduced. The aim of the update was to simplify the actual approach.

Is it really simplified? Let us have a closer look! I will be using Angular v16, so stay tuned for most feature usage!

👉 Also, check out some Angular dev tools you could try in 2023.

The idea is to leverage Dynamic Parameters to determine which Angular Component should be dynamically created. Therefore our route configuration should look like this:

Root Routes with lazy loaded Services Component

I am using lazy loading with a standalone component, which is why I am using loadComponent with import syntax (in lines 7–8). Our actual focus should be on line 6, where dynamic :id is being declared. This way we are declaring a dynamic parameter named “id”, which will be available with ActivatedRoute class injected into constructor (via dependency injection mechanism) like in the code example below:

Initial ServicesComponent implementation

To get the most recent parameters from the URL you can subscribe to this.route.params stream (line 18). If there’s no parameter declared within the URL (`/services`), you will receive an empty object ({}).

Remember:

ALWAYS unsubscribe when your component is being destroyed! (There are plenty of ways to achieve this! But it’s a topic for another time). If you don’t, the garbage collector will not know that you’re not using subscription anymore and you will face memory leak!
Read more about memory leaks and techniques to prevent them:

Now we are all set to get to the bottom of our main topic. Angular Team suggests creating a separate directive, which will contain ViewContainerRef class injected, so it can be reused anywhere without the need of passing additional dependency injection to every component where dynamic components might be needed. GOOD IDEA! Here’s what the example directive implementation might look like:

Now you need to simply use it within the html template of services.component.

Example usage of ComponentHostDirective

I am using the newly introduced (in v16) self-closing tag syntax, which you might have known from React already. Looks a little bit clearer right? It is all about making our code a little bit cleaner and easier to read.

Ok, my directive is already in place, so now I am able to use @ViewChild decorator to get to the directive within our services.component class and access our publicly available viewContainerRef! Here’s how services.component.ts class should look now:

ComponentHostDirective has been imported to our standalone component and the actual instance from the HTML template is already available under this.componentHost attribute.

Let us now create a method which will handle component creation:

I am destructuring viewContainerRef so I can use it for all my needs. Firstly, I need to make sure, that there’s no leftover from previous emissions. That is why I am calling the viewContainerRef.clear() method, to remove any previously created component instance.

Secondly, I am creating a brand new instance of my component based on the service id, taken from the servicesComponentFactory definition.

This is my own implementation, has nothing to do with actual dynamic component creation. It is more like a convenience technique to ensure proper mapping between parameters and component type. You can also ensure some default behavior for the factory on your own. We’re not preparing bulletproof solutions now, just showing examples!

Here’s what the servicesComponentFactory definition looks like:

Need to highlight, how our data passed as an argument of the method looks like. It’s an interface which represents the data structure being passed to the created component instance:

I’ve also declared an enum which represents types of available services:

Now, let us hook the method into the parameters stream subscription:

Compared to our initial stream, I have added switchMap operator to switch every emission into another stream which will allow me to fetch data representing my service object.

Just to remind you: my expected parameters should be represented by ServiceTypes, and look like:

'consultancy' | 'trainings' | 'engineering'

That is why I need to transform those into the actual id representation, of type number (according to our Service interface).

I use switchMap, because of its nature. Once new parameter arrives and my data is still not there, I will not need my data anymore. I need to request new data, based on newly emitted id immediately. This is what switchMap operator does. Cancels previous request and sends a new one.

To summarize, the entire services.component.ts class should look like this:

ServicesComponent class with dynamically created child components

Just have a look at the imports at the top of the file! Barrel exports rock right?
More about barrel exports can be found here:
https://medium.com/bitsrc/how-ive-cleaned-up-my-application-with-barrel-exports-and-path-aliases-in-angular-16-27a216f46e29

That’s it! Our dynamic component creation is up and running! Looks really simple! Thanks for the update Angular Team!

Read more of my articles here!:

💡 Do you find yourself using the same Angular component for multiple projects? Consider using a component-management hub such as Bit. With Bit, you can harvest reusable Angular components from your codebase and reuse across all your projects. Bit comes with a component development environment for Angular that provides proper tools, configurations and runtime environment for your components, providing versioning, testing, and dependency management features to simplify the process.

Learn more here:

Build Angular Apps with reusable components, just like Lego

Bit’s open-source tool help 250,000+ devs to build apps with components.

Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.

bit.dev

Learn more

Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:

Micro-Frontends

Design System

Code-Sharing and reuse

Monorepo

--

--

JavaScript/Typescript experience with biggest corporates and scalable software, with focus on reactive / performance programming approach / high code quality.