How Directives Work?
Let's learn about the basic syntax and features of directives.
Basic notes and usage
Directives are classes marked by the @Directive
decorator, just like components are marked by the @Component
decorator.
Here’s an example:
@Directive({
selector: 'my-directive',
})
export class MyDirective {
...
}
We must declare directives if a module uses them. So, we need to add them into the declaration field of our NgModule
, like this::
@NgModule({
declarations: [
MyDirective
]
})
export class MyModule {
}
Components Versus Directives
There are lots of similarities between components and directives. The table below lists them:
Components | Directives | |
---|---|---|
HTML selector | Yes | Yes |
HTML template | Yes | No, however, it can modify the existing DOM. |
CSS stylesheet | Yes | No, however, it can change existing styles. |
DOM interaction | Yes, it’s a custom element | Yes, it can be a custom element, or an attribute of an existing element that modifies its behavior or appearance. |
Inputs / Outputs | Yes, they communicate with the parent component | Yes, they communicate with the component at the location that it’s used. |
In summary, here’s what we need to remember about the differences between components and directives:
- A component is a reusable set of DOM elements that creates a UI supplied with custom behavior.
- A directive is a reusable behavior that can be applied to existing DOM elements.
How do directives work?
There’s no single answer to this question because directives do many things and enhance codebases in many ways. We’ll discuss how later in this course. For now, let’s look at a basic overview.
An essential part of a directive is the constructor, which we can use to inject references that are crucial to our directive.
@Directive({
selector: '[appBold]'
})
export class BoldDirective {
constructor(el: ElementRef) {
el.nativeElement.style.fontWeight = 'bold';
}
}
In this example, we inject ElementRef
, which gives us access to the host DOM element. The host DOM element is the exact element upon which the directive is set. In the constructor code, we can set a bold font-weight style on nativeElement
, which is the actual DOM element.
In the directive constructor, we can inject far more than just a reference to the DOM element. Let’s assume we create this directive, declare it in our module, and now want to use it. How do we do that? We can answer that question by examining selectors.
Selector
The Selector property in the @Directive
decorator declaration is crucial to understanding how to use the given directive. The selector is simply a CSS selector we use to identify the directive in the template and apply its code to that element.
In CSS, we have a bunch of different selectors. Some of them are very specific while some are more broad.
Here’s a list of the available selectors:
- The
element-name
selects by element name. - The
.class
selects by class name. - The
[attribute]
selects by attribute name. - The
[attribute=value]
selects by attribute name and value. - The
:not(sub_selector)
is used only if there’s no match with thesub_selector
. - The
selector1, selector2
is used if theselector1
andselector2
match.
Let’s go back to our example:
@Directive({
selector: '[appBold]'
})
export class BoldDirective {
constructor(el: ElementRef) {
el.nativeElement.style.fontWeight = 'bold';
}
}
We used the selector
attribute. So, what does this tell us? Simply, whenever we specify the appBold
custom attribute, we apply BoldDirective
. The illustration below presents this concept:
Here is an example:
<p appBold>This text will be bold</p>
<p>This one will be regular</p>
First, we apply the directive to the <p>
element, which has our custom attribute. However, the next element doesn’t have that directive, so it remains the same.
Let’s see that in action:
<!--applying appBold directive on the <p> element--> <p appBold> Header 1</p> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
Selector abilities
The attribute selector is very popular because it can be applied to anything while giving implicit information about where it’s added. The developer needs to add the attribute to each element individually.
Let’s assume we want to add this directive to all the elements with the following CSS class:
class="header"
We would use the selector
attribute here and add it manually to every element that has this class. But, what if we add another element? What if there are too many elements to do this manually? In such cases, we would want to learn a process that will add it automatically to every element that meets our requirements, which we’ll learn to do in the next lesson.
Summary
In Angular, directives are similar to components. The main differences are that directives don’t have their own template and are applied to existing DOM elements.
Directives are applied to elements by CSS selectors, which are specified in the @Directive
declaration.