Directives
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)
- classes
- element type
- id
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
Built-in Directives
ngStyle
It allows us to set styling of elements based on some condition:
The getColor()
method would return some valid color string based on some
condition.
ngClass
It’s very similar to ngStyle
, but it applies classes based on some logic.
The .highlighted
CSS class will be applied to this paragraph only if it’s an
admin.
*ngIf
A conditional:
The “else” syntax really sucks compared to Vue.js… It would be easier to use
another *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
an app.
ngSwitch
Similarly to switch
in most programming languages, we have ngSwitch
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.
*ngFor
Iteration can be done with *ngFor
:
We can also get the index of the iteration with:
The i
variable may be used within the loop now.
Custom Directives
Some conventions:
- the file names for directive are usually in the format
{name}.directive.ts
. - the
selector
is usually camelCase.
Here’s a simple example:
Usage:
The background of the paragraph will be blue.
A few highlights:
- the
[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 (likep
). If it has a dot at the beginning, it would select elements with a specified class. - the
elementRef
in 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 beElementRef
. - it’s a good idea to use Renderer2.
- we can do something with our element.
ngOnInit
lifecycle 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:
@HostBinding
There’s an even easier way to modify DOM properties than using
references or
Renderer2. It’s a decorator called HostBinding
. It
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:
Setting isOpen
to true
adds the class open
to the element.
Directive’s Inputs
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:
The 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 appMyDirective
in
square brackets to communicate to the framework both of the meanings listed
above.
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
imlementation of *ifNot
:
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.
Basically, TemplateRef<any>
represents the WHAT, and the ViewContainerRef
represents the WHERE, helping our directive to do its job.