Comprehensive Guide to Directive Composition API in Angular
Published July 18, 2024 by T&S Software Admin
Angular, a robust front-end framework, provides a plethora of tools for developers to build dynamic web applications. One of these powerful tools is the Directive Composition API, which allows developers to apply reusable behaviors to components seamlessly. This article explores the ins and outs of the Directive Composition API, demonstrating its usage with practical examples and detailed explanations.
What is the Directive Composition API?
The Directive Composition API in Angular lets you apply directives to a component's host element directly from within the component TypeScript class. This feature enables encapsulation of reusable behaviors such as applying attributes, CSS classes, and event listeners to elements.
Adding Directives to a Component
To apply directives to a component, you add a hostDirectives
property to the component's decorator. Directives used this way are referred to as host directives.
@Component({
standalone: true,
selector: 'admin-menu',
template: 'admin-menu.html',
hostDirectives: [MenuBehavior],
})
export class AdminMenu { }
When Angular renders this component, it also creates instances of each host directive, applying their host bindings to the component's host element.
Including Inputs and Outputs
By default, the inputs and outputs of host directives are not exposed as part of the component's public API. However, you can explicitly include them by expanding the entry in hostDirectives
.
@Component({
standalone: true,
selector: 'admin-menu',
template: 'admin-menu.html',
hostDirectives: [{
directive: MenuBehavior,
inputs: ['menuId'],
outputs: ['menuClosed'],
}],
})
export class AdminMenu { }
This allows consumers to bind these inputs and outputs in a template:
<admin-menu menuId="top-menu" (menuClosed)="logMenuClosed()">
Adding Directives to Another Directive
The Directive Composition API also allows adding host directives to other directives, enabling the aggregation of multiple behaviors.
@Directive({...})
export class Menu { }
@Directive({...})
export class Tooltip { }
@Directive({
standalone: true,
hostDirectives: [Tooltip, Menu],
})
export class MenuWithTooltip { }
@Directive({
standalone: true,
hostDirectives: [MenuWithTooltip],
})
export class SpecializedMenuWithTooltip { }
When SpecializedMenuWithTooltip
is used, instances of Menu
, Tooltip
, and MenuWithTooltip
are created, with each directive's host bindings applied to the host element.
Host Directive Semantics
Directive Execution Order
Host directives execute their constructor, lifecycle hooks, and bindings before the component or directive they are applied to. This order allows components with host directives to override any host bindings specified by the host directive.
Example:
@Component({
standalone: true,
selector: 'admin-menu',
template: 'admin-menu.html',
hostDirectives: [MenuBehavior],
})
export class AdminMenu { }
Execution Order:
MenuBehavior
instantiatedAdminMenu
instantiatedMenuBehavior
receives inputs (ngOnInit
)AdminMenu
receives inputs (ngOnInit
)MenuBehavior
applies host bindingsAdminMenu
applies host bindings
Nested Host Directives
The execution order extends to nested chains of host directives.
@Directive({...})
export class Tooltip { }
@Directive({
standalone: true,
hostDirectives: [Tooltip],
})
export class CustomTooltip { }
@Directive({
standalone: true,
hostDirectives: [CustomTooltip],
})
export class EvenMoreCustomTooltip { }
Execution Order:
Tooltip
instantiatedCustomTooltip
instantiatedEvenMoreCustomTooltip
instantiatedTooltip
receives inputs (ngOnInit
)CustomTooltip
receives inputs (ngOnInit
)EvenMoreCustomTooltip
receives inputs (ngOnInit
)Tooltip
applies host bindingsCustomTooltip
applies host bindingsEvenMoreCustomTooltip
applies host bindings
Dependency Injection
Components or directives specifying hostDirectives
can inject instances of those host directives and vice versa. Both components and host directives can define providers, but if they both provide the same injection token, the component or directive with hostDirectives
takes precedence.
FAQs
What is the Directive Composition API in Angular? The Directive Composition API allows developers to apply directives to a component's host element directly within the component's TypeScript class, enabling reusable behaviors.
How do you add a directive to a component in Angular? You add a directive to a component by including it in the hostDirectives
property of the component's decorator.
Can you include inputs and outputs from host directives in a component's public API? Yes, you can explicitly include inputs and outputs by expanding the entry in hostDirectives
.
What is the order of execution for host directives and components? Host directives execute their constructor, lifecycle hooks, and bindings before the component or directive they are applied to.
Can you add host directives to other directives? Yes, the Directive Composition API allows adding host directives to other directives, enabling the aggregation of multiple behaviors.
How does dependency injection work with host directives? Both components and host directives can define providers. If they provide the same injection token, the component or directive with hostDirectives
takes precedence.
Conclusion
The Directive Composition API in Angular provides a powerful way to encapsulate and reuse behaviors across components and directives. By understanding and leveraging this API, developers can create more modular and maintainable code. Whether you're adding directives to a component, including inputs and outputs, or aggregating behaviors, the Directive Composition API enhances the flexibility and robustness of your Angular applications.For more in-depth articles, visit our blog.