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.
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:
- Using the Directive Composition API (recommended approach).
- 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:
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:
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! 🚀