Directives are a way to kind of decorate HTML element with some additional logic. Similarly to Components, they can be applied to element using:
- attributes (most often used)
- element type
For example, I could have this:
It would apply the
UnderlineDirective to the paragraph.
Directive is a TS class with a
@Directive decorator applied to it.
There are also some built-in directives.
Directives can be:
- “casual” - do not add/remove elements from the DOM
- structural - add/remove elements from the DOM
It allows us to set styling of elements based on some condition:
getColor() method would return some valid color string based on some
It’s very similar to
ngStyle, but it applies classes based on some logic.
.highlighted CSS class will be applied to this paragraph only if it’s an
The “else” syntax really sucks compared to Vue.js… It would be easier to use
*ngIf with reversed condition.
*ngIf Behind the Scenes
Angular transforms the
*ngIf into something like this:
This is the “raw” version of
ngIf. It would actually work if we placed it in
switch in most programming languages, we have
directive in Angular. This one is a bit unique, because we use it as a
combination of a few directives.
Only one case is displayed at a time.
Iteration can be done with
We can also get the index of the iteration with:
i variable may be used within the loop now.
- the file names for directive are usually in the format
selectoris usually camelCase.
Here’s a simple example:
The background of the paragraph will be blue.
A few highlights:
[appMyDirective]selector is in square brackets, which means that the directive will be used as an attribute. If our selector was without the square brackets, it would be specifying an HTML element that this directive would be applied to (like
p). If it has a dot at the beginning, it would select elements with a specified class.
elementRefin the constructor is the element that the directive was applied to. It gets injected into the instance automatically by Angular. The name can be whatever we want, just the type needs to be
- it’s a good idea to use Renderer2.
- we can do something with our element.
ngOnInitlifecycle hook is a good place to do it.
Reacting to Events
Directives can listen to events on the elements they are attached to. Here’s an example:
There’s an even easier way to modify DOM properties than using
Renderer2. It’s a decorator called
allows to bind to a specified property on the DOM element to access it easily.
Here’s an example:
Another example shows how we can toggle a class on some element:
true adds the class
open to the element.
Our directives can support some input arguments, very similarly to the way how Components accept inputs. This way, users of the directive can have some influence on how it works.
Here’s an example:
This is a silightly modified code compared to the previous example. Now the color applied to our element is no longer hardcoded. Here’s how the binding is done in the template:
Angular figures out if the provided input belongs to the directive or the element itself. (What if there’s a conflict?)
Reusing directive’s name for an input
Some built-in directives, such as
[ngClass] accept the inut (a class name)
directly under the directive’s name, like this:
We can do it as well in our directives:
We’d use that directive as follows:
appMyDirective has two meanings now:
- it’s an attribute which marks DOM elements that we want to apply our directive to;
- it’s an inut of our directive allowing users to set some value.
Angular allows us to use the shorthand of including the
square brackets to communicate to the framework both of the meanings listed
Custom Structural Directives
As it was described in the *ngIf section, structural components have a
star prefixing the directive’s name. That causes the elements to be placed in
<ng-template>, which is Angular’s way to specify templates.
Here’s an example of how to build our own structural components. This is an
We’d use it like this:
In the directive’s class we used the following (auto-injected) elements:
TemplateRef<any>- this represents the
<ng-template>that is generated due to a ’*’
ViewContainerRef- this represents the place where the element (that our directive is applied to) should be located.
TemplateRef<any> represents the WHAT, and the
represents the WHERE, helping our directive to do its job.