Anatomy of Angular Attribute @Directive selector
Directives provide a powerful addition to the Angular platform giving us the ability to define behaviours on any element without the need to write a component. Each HTML DOM element can have zero or more directives attached, providing unlimited possibilities.
In fact Angular components are a specific type of attribute directive that contain a template.
This article is specifically covering the usage of the selector property of the @Directive decorator.
Selectors can be declared using any of the following as per the angular documentation:
- element name or tag name
- [attribute] or [attribute=value]
- .class
- :not(sub_selector)
- selector1, selector2
The above are essentially DOM query selectors used to target one or more HTML elements in the DOM.
HTML Element
Before we start let’s provide some context of the anatomy of a HTML element.
A HTML element is can be broken down into individual segments:
- Element — is a html element tag name
- Class — is CSS class name associated with the element
- Attribute — provides additional information about HTML elements
The Foo Bar Baz example below will be used throughout the remainder of the this article.
Basic Selectors
Selectors fall into one of the three categories:
1. Element Name Selector
Using the element name selector you can target specific HTML element tags, this can be either a standard Html element or a Angular component. The example below is targeting all element tags with the name foo.
2. Attribute Selector
Using the attribute selector you can target specific HTML elements that contain the specific attribute(s). Attributes selectors are contained within square brackets [ ].
The example below is targeting all elements that have an attribute with the name baz.
Attribute selectors can also be further restricted to the value the attribute is being set to. The example below is targeting all attributes that have an attribute with the name baz with a value of blah.
3. Class Selector
Using the class selector you can target specific HTML elements with the specified CSS class names. The CSS selector is prefixed with a dot, which is the same as CSS syntax.
The example below is targeting all elements that have a CSS class names containing bar.
One caveat with the class selector is that you cannot target class names that are dynamically inserted into the DOM using an expression binding either via a class binding or NgClass attribute directive.
Chaining Selectors ( and )
Each of the selectors (element, class and attribute) can be chained together to narrow the query for the relevant HTML elements like “selector and selector”. There are no tokens that separate each of the chained selectors, the selectors are separated using selector token itself either using square brackets for attribute selectors or a dot for class selectors.
The example above will select all HTML elements that have an element tag named foo and an attribute named baz. Notice there is no space between the each of the individual selectors, only the token the square brackets is used to delineated between the selectors.
The only caveat with the order of selectors is a class selector cannot be succeeded by an element selector, as there is no symbol to separate the two selectors. Also a element name selector can only be specified once otherwise the directive will not find any elements.
The above example will select all HTML elements with an element name of foo and a CSS class name containing bar. The order cannot be reversed otherwise the selector would be querying for elements with a class name of barfoo, which is not desired.
Chaining selectors can only include a single element name selector with zero or more of either class name or attribute selectors.
The above example will select all HTML elements with an element name of foo, a CSS class name containing bar and an attribute named baz.
Exclusion Selectors
Querying for specific HTML elements sometimes there is a need to exclude specific elements that contain either a class name or attribute.
To exclude specific HTML elements use the keyword :not(…) with the specific selector inserted between the round brackets.
The example below will select all HTML elements with an element name of foo but exclude those with an attribute named baz.
Exclusion selectors can be chained together to further refine the query.
The example above will select all HTML elements with an element name of foo but exclude those with an attribute name baz and a CSS class containing bar.
Combining Selectors ( or )
All the selectors combinations above can be combined together in groups using a comma as the separating token to create a OR like query. There is no limit on the number of selectors that can be combined together for targeting of the directive. Where their are multiple possible matches found, only a single instance of the directive will be instantiated for the HTML DOM element.
The example above will select all HTML elements with an element name of foo or with an attribute named baz. If a HTML element contains both matching criteria the directive will only be attached once.
Angular Forms Directive Example
Directives are used to implement many of the features that we use in forms and other parts of the angular platform.
The example above is the DefaultValueAccessor directive extracted from the forms module. The selector combines all of the various selectors (element, attribute), chaining selectors, exclusion selectors and combining these selectors to target various HTML elements.
Let’s break this selector down into various parts:
- Select input elements with formControlName attribute but not with attribute with attribute type=checkbox.
- Select textarea elements with formControlName attribute.
- Select input elements with formControl attribute but not with attribute with attribute type=checkbox.
- Select textarea elements with formControl attribute.
- Select input elements with ngModel attribute but not with attribute with attribute type=checkbox.
- Select textarea elements with ngModel attribute.
- Select elements with ngDefaultControl attribute.
Conclusion
Angular’s attribute directives are an extremely powerful feature of the Angular platform providing you a way to attach additional behaviour to any HTML element.
The Angular Components makes extensive use of attribute directive to attach additional behaviours to various standard Html elements such matInput which is targeted to input Html element.
In my next post I will be covering some interesting use cases of using attribute directives targeting input elements to restrict keyboard interaction.