How to Add a Directive Programmatically in Angular +15

George Hulpoi2 min read · Jan 9

Adding a directive programmatically in Angular has always been a challenge, especially since Angular does not provide a built-in method for dynamically creating directives. However, with Angular 15+, the introduction of the Directive Composition API offers a way to programmatically attach directives to components, making the process much simpler.

If you’re looking to add a directive programmatically in Angular, this guide will walk you through how to achieve it using the Directive Composition API.

Summary

Angular allows programmatic rendering of components (see Programmatically Rendering Components), but it does not provide a straightforward way to dynamically create a directive. Even if a component class extends a directive, Angular’s lifecycle and change detection mechanisms do not naturally support dynamic directive creation.

There are two possible approaches:

  1. Using the Directive Composition API (recommended approach).
  2. Manually instantiating the directive and handling its lifecycle (which can be cumbersome and non-intuitive).

This guide focuses on the Directive Composition API, which allows us to dynamically add directives to components without worrying about lifecycle management.

For example, let's say we want to dynamically attach the RouterLink directive to a component.

We will create a wrapper component that includes the RouterLink directive:

12345678910111213141516
import {Component, ViewEncapsulation} from '@angular/core';
import {RouterLink} from '@angular/router';

@Component({
    selector: 'a',
    template: '<ng-content></ng-content>',
    standalone: true,
    encapsulation: ViewEncapsulation.None,
    hostDirectives: [
        {
            directive: RouterLink,
            inputs: ['routerLink', 'fragment', 'queryParamsHandling', 'queryParams'],
        },
    ],
})
export class AnchorComponent {}

By adding the directive to hostDirectives, we expose its inputs and seamlessly integrate it into our component.

Now, let’s render our directive dynamically inside another component:

12345678910111213141516171819202122
import {Component, ViewContainerRef, ViewChild, OnInit, Renderer2} from '@angular/core';
import {AnchorComponent} from './anchor';

@Component({
    selector: 'app',
    standalone: true,
    template: ` <ng-container #vc></ng-container> `,
})
export class App implements OnInit {
    @ViewChild('vc', {static: true, read: ViewContainerRef}) vc!: ViewContainerRef;

    constructor(private readonly renderer: Renderer2) {}

    ngOnInit(): void {
        const comp = this.vc.createComponent(AnchorComponent, {
            projectableNodes: [[this.renderer.createText('It works!!')]],
        });

        comp.setInput('routerLink', '/');
        comp.changeDetectorRef.detectChanges();
    }
}

Now, when the App component initializes, it dynamically creates the AnchorComponent with the RouterLink directive attached, and sets its routerLink input.

You can see a working implementation of this approach on StackBlitz.

By using the Directive Composition API, we can add a directive programmatically in Angular without manually managing its lifecycle. This approach is particularly useful when working with third-party directives or dynamically generated elements.

If you’ve been searching for a way to dynamically create a directive in Angular, this method provides a clean, efficient, and Angular-friendly solution.

Happy coding! 🚀