Avoid Namespace Clashes with Directives

Part 4 of Advanced Angular Component Patterns

Isaac Mann
Angular In Depth
2 min readFeb 6, 2018

--

Photo by Samuel Zeller on Unsplash

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 Inputs and Outputs 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 Inputs 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.

Outcome:

--

--