When to use Angular’s Dynamic Components

Damodara Puddu
5 min readJan 7, 2022

--

Being a fairly opinionated framework, Angular is easy to learn and start using, following its design patterns. Dynamic Components introduce more flexibility than what the average Angular developer may be used to, let’s take a look at when that flexibility comes in handy.

What are Dynamic Components ?

Dynamic Components allow us to create and render components at runtime. This is achieved by referring to a container using a template variable and inject newly created components into it as a result of some user interaction. In Angular 13 this is as simply as that although in previous version a little more boilerplate code is needed. Let’s look at the plumbing involved in both cases:

Using ViewChild with the above options we can get ahold of a reference to the container for our dynamically generated component, this is where we can attach its view. In older versions of Angular, we need to inject the ComponentFactoryResolver and use this to resolve a factory for the component type we’re trying to create. That factory can then be used to create the component by passing it to the ViewContainerRef. In Angular 13, we can create a component by passing the type directly to the view container ref (one more reason to upgrade 😊 ).

Now that we know how to dynamically create components and attach their view to the DOM, let’s take a look at a couple of use cases where we might want to apply this.

Notification

We may want a section of the page to display components that haven’t been added to the codebase yet or perhaps their structure is not known. We can write up a container component which will dynamically create these new components, the only thing we need it’s their type.

Let’s say we need a notification, like a popup warning, to be displayed above any other content on the page and we want to provide flexibility on the content this can have.

Our notification component is rather simple: it has an icon that closes the notification upon clicking it and a container for whatever component we want as the notification content, we just need to provide its Type.
You may have noticed that the childComponentType is not an input and onClose$ is not an output. That is because instead of having to place the notification component inside the templates of other components and having to manage its input and handle its outputs, we are going to control its presence on the DOM through a service.

How would we achieve this you may wonder ? Using Dynamic Components 😄

First, we need to decide which component will be containing our notification. We’ll assign this by injecting the notification service we’ll be creating in a moment and give it the ViewContainerRef of the component we want as container.

We’re going with the AppComponent here but you may want a modal to contain the notification, in which case, you’d set the service property with the modal’s viewRef in the modal component instead.

First of all, we set ourselves up by defining a class variable to hold our notification instance and the ViewContainerRef we have just set in the AppComponent.
To use this service we call the newNotification method providing the type of the component we want to be rendered inside our notification. If a notification instance already exists, we close it, then we open a new notification and listen for when this is closed.
When we call openNotification the magic happens: using the provided containerElementViewRef we create a notification straight into the page body as the value of the ref comes from the AppComponent. Once we created our notification we can assign to it the desired content type so that its content as well can be dynamically created.
When we want to close the notification we simply detach its view from the DOM and destroy its instance.

You’re welcome visual learner 😎

In this example we catered for unstructured content for a generic component and centralised the logic that handles basic interactions with our notification by encapsulating it in a service.

Play around with the above example.

Accordion

Dynamic Components can also improve our code DRYness, particularly when we’re dealing with components that require a lot of inputs and content setup.

Let’s take the case of a simple accordion component. This will have headers that when clicked will reveal the content in their corresponding slot. If we require the slot content to be a complex component (or a number of them) we may end up having to write a lot of setup logic in our accordion template. Instead let’s drive this content through a config file.

Each slot will have an identifier, an header, a content, and an open property. The content can contain simple text as in the first slot or contain an actual component that we want rendered inside that slot, along with the component inputs.

Let’s take a look at how our accordion component can use the config to render content.

Let’s look at the template first. For each slot in the config data we display the header and then check if the slot content has a componentType property: if it does, we know it’s going to need a template for the component to be created in, if it doesn’t we simply render the slot content as simple text.

In the accordion component we store those templates we generated in a QueryList. Then, once the view has initialised we iterate through the config data and check if any of our slot content has a componentType. When we find one, we grab the next available template from the list, create the component of componentType into it, and bind its input values.
The rest is just a little logic to open and close the slots.

The config can have any type of component and can be delivered from anywhere, possibly even from outside the codebase. This approach gives us a lot of flexibility to define the contents of our accordion, while using very little setup code.

Play around with the above example.

Conclusion

Dynamic Components can be used to make the way we render our components across the frontend more flexible and dynamic.
They can also be used to decrease your bundle size by importing the component just before creating where needed.

Resources & Credits

--

--