Combining Angular Directives with the Directive Composition API
Posted: 12/18/2022
Categories:
angular
The Directive Composition API brings with it a couple benefits:
- reduce code duplication
- combine directives to form composite directives
It's the second benefit that this post focuses on.
If you are unfamiliar with the Directive Composition API, you can read my introduction.
The Scenario
Across our app, we have a set of forms field components. To assist with consistency and code re-use, we've created the following directives to apply to those fields:
InvalidFieldDirective
: Styles the field in the event it's invalid.RequiredFieldDirective
: Adds an "*" and styles the field to note it's required.TooltipDirective
: Displays a tooltip.
Sometimes we need some of those, but on other occasions we need them all.
This is one example of where the Directive Composition API can come in handy.
Using the Directive Composition API we can create a directive that combines all those directives.
How?
Making the Component Standalone
First of all, we need to make sure that each of the directives are standalone.
To do this, first add the standalone
property in the directive's decorator and set it to true
:
@Directive({
selector: '[appMyDirective]',
standalone: true
})
You then need to remove your directive from a module's declarations
array if it features in one.
Creating your Composite Directive
The act of creating a composite directive is actually rather simple.
Create a directive that will eventually combine the other directives:
@Directive({
selector: "[appStandardFormLabel]",
standalone: true,
})
export class StandardFormLabelDirective {}
We can now add the hostDirectives
property to our directive to include the directives we want it to apply:
@Directive({
selector: "[appStandardFormLabel]",
standalone: true,
hostDirectives: [
InvalidFieldDirective,
RequiredFieldDirective,
TooltipDirective,
],
})
export class StandardFormLabelDirective {}
Now that we have our composite directive, we can put it to use:
<app-form-label app-standard-form-label></app-form-label>
We have a problem though: some of our directives have inputs that are required:
LIST THE DIRECTIVES AND THEIR INPUTS HERE
We can solve this by specifying the inputs for each of the directives:
EXAMPLE
We then pass the inputs in as we would any other directive:
EXAMPLE