This article focuses on Angular directives — what are they, how to use them, and to build our own.
Directives are perhaps the most important bit of an Angular application, and if we think about it, the most-used Angular unit, the component, is actually a directive.
An Angular component isn’t more than a directive with a template. When we say that components are the building blocks of Angular applications, we’re actually saying that directives are the building blocks of Angular applications.
At the core, a directive is a function that executes whenever the Angular compiler finds it in the DOM. Angular directives are used to extend the power of the HTML by giving it new syntax. Each directive has a name — either one from the Angular predefined like ng-repeat, or a custom one which can be called anything. And each directive determines where it can be used: in an element, attribute, class or comment.
By default, from Angular versions 2 and onward, Angular directives are separated into three different types:
As we saw earlier, components are just directives with templates. Under the hood, they use the directive API and give us a cleaner way to define them.
The other two directive types don’t have templates. Instead, they’re specifically tailored to DOM manipulation.
Attribute directives manipulate the DOM by changing its behavior and appearance.
We use attribute directives to apply conditional style to elements, show or hide elements or dynamically change the behavior of a component according to a changing property.
These are specifically tailored to create and destroy DOM elements.
Some attribute directives — like hidden, which shows or hides an element — basically maintain the DOM as it is. But the structural Angular directives are much less DOM friendly, as they add or completely remove elements from the DOM. So, when using these, we have to be extra careful, since we’re actually changing the HTML structure.
Using the existing directives in Angular is fairly easy, and if you’ve written an Angular application in the past, I’m pretty sure you’ve used them. The ngClass directive is a good example of an existing Angular attribute directive:
<span><span><span><p</span> [ngClass]<span>="{'blue'=true, 'yellow'=false}"</span>></span> </span> Angular Directives Are Cool! <span><span><span></p</span>></span> </span> <span><span><span><style</span>></span><span> </span></span><span><span> <span><span>.blue</span>{color: blue} </span></span></span><span><span> <span><span>.yellow</span>{color: yellow} </span></span></span><span><span></span><span><span></style</span>></span> </span>
So, by using the ngClass directive on the example below, we’re actually adding the blue class to our paragraph, and explicitly not adding the yellow one. Since we’re changing the appearance of a class, and not changing the actual HTML structure, this is clearly an attribute directive. But Angular also offers out-of-the-box structural directives, like the ngIf:
@Component({ selector: 'ng-if-simple', template: ` <span><span><span><button</span> (click)<span>="show = !show"</span>></span>{{show ? 'hide' : 'show'}}<span><span></button</span>></span> </span> show = {{show}} <span><span><span><br</span>></span> </span> <span><span><span><div</span> *ngIf<span>="show"</span>></span>Text to show<span><span></div</span>></span> </span>` }) class NgIfSimple { show: boolean = true; }
In this example, we use the ngIf directive to add or remove the text using a button. In this case, the HTML structure itself is affected, so it’s clearly a structural directive.
For a complete list of available Angular directives, we can check the official documentation.
As we saw, using Angular directives is quite simple. The real power of Angular directives comes with the ability to create our own. Angular provides a clean and simple API for creating custom directives, and that’s what we’ll be looking at in the following sections.
Creating a directive is similar to creating a component. But in this case, we use the @Directive decorator. For our example, we’ll be creating a directive called “my-error-directive”, which will highlight in red the background of an element to indicate an error.
For our example, we’ll be using the Angular 2 quickstart package. We just have to clone the repository, then run npm install and npm start. It will provide us a boilerplate app that we can use to experiment. We’ll build our examples on top of that boilerplate.
Let’s start by creating a file called app.myerrordirective.ts on the src/app folder and adding the following code to it:
import {Directive, ElementRef} from '@angular/core'; @Directive({ selector:'[my-error]' }) export class MyErrorDirective{ constructor(elr:ElementRef){ elr.nativeElement.style.background='red'; } }
After importing the Directive from @angular/core we can then use it. First, we need a selector, which gives a name to the directive. In this case, we call it my-error.
Best practice dictates that we always use a prefix when naming our Angular directives. This way, we’re sure to avoid conflicts with any standard HTML attributes. We also shouldn’t use the ng prefix. That one’s used by Angular, and we don’t want to confuse our custom created Angular directives with Angular predefined ones. In this example, our prefix is my-.
We then created a class, MyErrorDirective. To access any element of our DOM, we need to use ElementRef. Since it also belongs to the @angular/core package, it’s a simple matter of importing it together with the Directive and using it.
We then added the code to actually highlight the constructor of our class.
To be able to use this newly created directive, we need to add it to the declarations on the app.module.ts file:
<span><span><span><p</span> [ngClass]<span>="{'blue'=true, 'yellow'=false}"</span>></span> </span> Angular Directives Are Cool! <span><span><span></p</span>></span> </span> <span><span><span><style</span>></span><span> </span></span><span><span> <span><span>.blue</span>{color: blue} </span></span></span><span><span> <span><span>.yellow</span>{color: yellow} </span></span></span><span><span></span><span><span></style</span>></span> </span>
Finally, we want to make use of the directive we just created. To do that, let’s navigate to the app.component.ts file and add the following:
@Component({ selector: 'ng-if-simple', template: ` <span><span><span><button</span> (click)<span>="show = !show"</span>></span>{{show ? 'hide' : 'show'}}<span><span></button</span>></span> </span> show = {{show}} <span><span><span><br</span>></span> </span> <span><span><span><div</span> *ngIf<span>="show"</span>></span>Text to show<span><span></div</span>></span> </span>` }) class NgIfSimple { show: boolean = true; }
The final result looks similar to this:
In the previous section, we saw how to create an attribute directive using Angular. The approach for creating a structural behavior is exactly the same. We create a new file with the code for our directive, then we add it to the declarations, and finally, we use it in our component.
For our structural directive, we’ll implement a copy of the ngIf directive. This way, we’ll not only be implementing a directive, but also taking a look at how Angular directives handle things behind the scenes.
Let’s start with our app.mycustomifdirective.ts file:
import {Directive, ElementRef} from '@angular/core'; @Directive({ selector:'[my-error]' }) export class MyErrorDirective{ constructor(elr:ElementRef){ elr.nativeElement.style.background='red'; } }
As we can see, we’re using a couple of different imports for this one, mainly: Input, TemplateRef and ViewContainerRef. The Input decorator is used to pass data to the component. The TemplateRef one is used to instantiate embedded views. An embedded view represents a part of a layout to be rendered, and it’s linked to a template. Finally, the ViewContainerRef is a container where one or more Views can be attached. Together, these components work as follows:
Directives get access to the view container by injecting a ViewContainerRef. Embedded views are created and attached to a view container by calling the ViewContainerRef’s createEmbeddedView method and passing in the template. We want to use the template our directive is attached to so we pass in the injected TemplateRef. — from Rangle.io’s Angular 2 Training
Next, we add it to our declarators:
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { MyErrorDirective } from './app.myerrordirective'; import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent, MyErrorDirective ], bootstrap: [ AppComponent ] }) export class AppModule { }
And we use it in our component:
<span><span><span><p</span> [ngClass]<span>="{'blue'=true, 'yellow'=false}"</span>></span> </span> Angular Directives Are Cool! <span><span><span></p</span>></span> </span> <span><span><span><style</span>></span><span> </span></span><span><span> <span><span>.blue</span>{color: blue} </span></span></span><span><span> <span><span>.yellow</span>{color: yellow} </span></span></span><span><span></span><span><span></style</span>></span> </span>
The kind of approach provided by structural directives can be very useful, such as when we have to show different information for different users based on their permissions. For example, a site administrator should be able to see and edit everything, while a regular user shouldn’t. If we loaded private information into the DOM using an attribute directive, the regular user and all users for that matter would have access to it.
We’ve looked at attribute and structural directives. But when should we use one or the other?
The answer might be confusing and we can end up using the wrong one just because it solves our problems. But there’s a simple rule that can help us choose the right one. Basically, if the element that has the directive will still be useful in the DOM when the DOM is not visible, then we should definitely keep it. In this case, we use an attribute directive like hidden. But if the element has no use, then we should remove it. However, we have to be careful to avoid some common pitfalls. We have to avoid the pitfall of always hiding elements just because it’s easier. This will make the DOM much more complex and probably have an impact on overall performance. The pitfall of always removing and recreating elements should also be avoided. It’s definitely cleaner, but comes at the expense of performance.
All in all, each case should be carefully analyzed, because the ideal solution is always the one that has the least overall impact on your application structure, behavior and performance. That solution might be either attribute directives, structural directives or, in the most common scenario, a compromise between both of them.
In this article, we took a look at Angular directives, the core of Angular applications. We looked at the different types of directives and saw how to create custom ones that suit our needs.
I hope that this article was able to get you up and running with Angular directives. If you have any questions, feel free to use the comment section below.
Angular Directives are classified into three types: Component Directives, Attribute Directives, and Structural Directives. Component Directives, as the name suggests, are directives with a template. They are essentially Angular components. Attribute Directives are used to change the behavior, look, and feel of a DOM element. Structural Directives, on the other hand, are used to manipulate the DOM layout by adding, removing, or replacing elements in the DOM.
Creating a custom directive in Angular involves a few steps. First, you need to import the Directive decorator from the Angular core. Then, you need to define a directive class and decorate it with the @Directive decorator. The selector property in the decorator should match the name you want to use for your directive. Finally, you need to add your directive to the declarations array in your NgModule.
Angular provides several built-in directives that you can use in your templates. For example, you can use the *ngIf directive to conditionally render elements, or the *ngFor directive to render a list of items. To use these directives, you simply add them to your template with the appropriate syntax.
In Angular, a component is a type of directive that has a template and is tied to a specific view. A directive, on the other hand, is a way to add behavior to an element in the DOM. While components are used to create UI widgets, directives are used to add behavior to existing elements.
Data binding in Angular directives can be done in several ways. One common way is through property binding, where you bind a property of a DOM element to a property of your component. You can also use event binding to respond to user actions, or two-way binding to keep your model and view in sync.
Testing a directive in Angular involves creating a test component that uses the directive, and then testing that component. You can use the TestBed utility to create a dynamic test component, and then use the ComponentFixture to interact with the component and its directive.
Yes, you can use multiple directives on a single element in Angular. However, you should be aware that the order in which directives are applied can affect the final result. Angular applies directives in the order they are listed in the template, so you should list your directives in the order you want them to be applied.
You can pass parameters to a directive in Angular using the @Input decorator. This allows you to bind a property of your directive to a value in your component. You can then use this value inside your directive to control its behavior.
To create a shared directive in Angular, you need to define your directive in a shared module. You can then import this shared module into any other module where you want to use the directive. This allows you to reuse the same directive across multiple components or modules.
Debugging a directive in Angular can be done using the Angular DevTools extension for Chrome and Firefox. This tool allows you to inspect your application’s components, directives, and services, and see their current state and dependencies. You can also use the console to interact with your application and debug issues.
The above is the detailed content of A Practical Guide to Using and Creating Angular Directives - SitePoint. For more information, please follow other related articles on the PHP Chinese website!