Avoid Namespace Clashes with Directives
Part 4 of Advanced Angular Component Patterns
AngularInDepth is moving away from Medium. More recent articles are hosted on the new platform inDepth.dev. Thanks for being part of indepth movement!
‹ 03b Enhance Components with Directives
05 Handle Template Reference Variables with Directives ›
Warning: Using multiple directives on the same html element can cause namespace clashes.
Not only can the selector for a directive clash with another directive, but Input
s and Output
s for those directives can clash with each other. When they have the same name, Angular doesn’t complain — it just applies the logic to both directives. In some cases, this is exactly what we want. However, sometimes it can cause unexpected behavior.
Goal:
Avoid namespace clashes with multiple directives on the same element.
Implementation:
Since the toggle
and withToggle
directives both apply to a <toggle>
element, we’ll illustrate the problem by adding a label
Input
to both of them. Now when we set <toggle label="some label">
the value is being set on both directives. The only way to give users the ability to specify the Input
for one directive and not the other is to prefix the Input
s to differentiate them.
The official Angular style guide warns that you should prefix your directive names, but you also need to be careful to prefix your Input
and Output
names.
Note: Pay special attention to avoid overloading a native DOM event with an Output
or overloading a native HTML attribute with an Input
. There’s no way of knowing all the possible names other people might use in their apps/libraries, but you can easily find out what the existing spec is and not overload it unless you’re doing it intentionally.
One way to add a prefix to each directive’s label
property is by adding a string inside the Input
decorator, like this:
// In withToggle.directive.ts
@Input('withToggleLabel') label;// In toggle.directive.ts
@Input('toggleLabel') label;
This solution requires that you can change the source code of at least one of the conflicting directives. Trying to work around two third party directives that are using the same Input
or Output
name is a tricky problem that I won’t try to solve here.