Software systems to innovate and grow

The usage of Angular Directives

By Engineering Team November 11, 2016 10 mins read

When we started to learn to code, we were taught to write in a particular way or style. In Angular, you have to use different types of directives as part of the language. Today we are showing you three ways on how to use those different types of directives.

3 Types of Angular Directives and When to Use Them

Directives are the building blocks of angular applications. Every time you see or use something like <my-app> or <div *my-directive>, you are using some form of an Angular directive.

Angular Directives have gone through a massive overhaul from version 1.x.

If you’ve spent time working with Angular 1.x, the code below will look familiar:

You can already see a lot of boilerplate code here – angular.module..., then .directive... and the not so pretty looking return object.

Angular 1.5 made things just a little bit better with the introduction of the component syntax. It looked something like this:

Looks much better. But still not as elegant as all the other object-oriented, modular languages and frameworks. The code still looks clunky and still has dependency injection and data binding complication.

Now here’s an Angular 2 directive:

Even if you know absolutely nothing about Angular, you can see how simple and elegant this new syntax is.

The striking differences between the Angular 2 syntax and the syntax of its predecessors include a class based approached, the @Directive annotation and lack of the app.directive...-like boilerplate code.

Let’s break down the code in the directive above –

1. The import statement

This statement gives us access to the Directive function decorator from the angular/core library.

If you haven’t started working with ES6 yet (start now!): the import statement imports classes, functions, and variables exported by other external modules / files.

When we start a new Angular 2 project, we install a bunch of dependencies using npm install. The @angular libraries are installed at that time. We can then reference these libraries using the syntax above.

2. @Directive

What would the directive code above look like without @Directive?

That’s it. It’s just another javascript class being exported. Nothing special about it. The @Directive decorator is what makes this class so special.

@Directive simply adds metadata to the plain MyDirective class. This allows angular to treat this class differently. That means that JavaScript doesn’t care about these decorators, only Angular does.

At this point, if you’re curious or you’re confused about the difference between annotators and decorators, ThoughtRam has a great article that will tell you about the difference between annotators and decorators in Angular 2.

For this purpose of this article you can use these words interchangeably.

3. The export statement

The final thing we do when creating this directive is export the class.

This allows the directive to be imported and used throughout the application. You can configure which modules can use this directive by declaring it under the declarations and exports of the module that contains this directive.

Now that you know what directives are and the code you need to create them, let’s write a simple directive.

How to Write an Angular 2 Directive

If you’d like to follow along with this tutorial, we’ve got a git repo that you can clone. To get started, run this command.

git clone https://github.com/cartab/learn-directives

After the repository has been cloned, install the dependencies using npm install. Your computer may require a sudo before these commands.

Once you’ve got everything install, you can start the app using ng serve. This will spin up a server on http://localhost:4200 and serve the angular application for this tutorial.

Now that we have the project running, let’s look at the first directive. Run git checkout simple-component and wait for webpack to bundle your files up and spit out webpack: bundle is now VALID..

If you look at src/app/app.component.ts, you can see the first type of directive.

Wait! A Component IS a directive?

Absolutely.

A component is nothing but a directive with a template. You can think of a component as a display or UI directive. It has some basic logic and renders HTML.
Components are the big daddy of directives. They are the most frequently used directives and can be nested in other components.

Let’s look at the syntax of the component (Directive) we have right now.

The template looks like…

This directive imports the annotation from the @angular/core module, adds the metadata and finally exports the class.

What does title = 'app works!' do?

It allows us to pass data to the HTML template. The template can render this variable’s data using the {{}} double curly braces syntax we use when writing Angular 1.x code.

Even though components are directives, the metadata properties we set for components and directives are different. This is mainly because (non-component) directives serve purposes other than building UI.

We won’t be diving deeper into Components and their metadata properties in this article. You can read more about it in an upcoming article.

Now let’s look at the other two kinds of directives.

Structural Directives

We use structural directives for DOM manipulations. ngFor and ngIf are two examples of Angular Structural directives built into the Angular library.

If you are following along with the git repo that you cloned above, run git checkout structural-directive.

Here’s a simple structural directive we wrote that is a custom implementation of the ngIf directive provided by Angular.

Let’s go through this code together, starting with the selector.

This is almost like a Component. The difference is the enclosure in [] square brackets. This is to tell angular to apply this directive to any element having the attribute mySD.

The main logic for the structural directive is in the class definition.

The first thing to notice is the constructor.

The constructor receives two arguments – the TemplateRef and the ViewContainerRef. To understand what these are, we need to look at how Angular process directives.

1. How Angular Sees Directives

Every time we use the syntax *directive as in *ngIf or *ngFor, Angular does some magic on the element.

For example, let’s look at the code below:

Here we apply the *ngIf directive to the paragraph tag and display the text if the watsonAround condition is true. At least this is how we see it when writing and reading this code.

Angular sees the same code a little differently.

Angular encapsulates the element in a template tag.

Why?

Because Angular processes template tags differently. Unlike browsers (which hide the contents of a template tag by default), Angular converts them to a script tag.
It uses this script tag to render DOM elements based on instructions in the directive.

This brings us back to the TemplateRef and ViewContainerRef variables.

2. TemplateRef and ViewContainerRef

The templateRef variable gives us access to the element in the <template> tag. This can be embedded into the view container.
The viewContainerRef is a reference to the container where we can attach the template.

3. Rendering the template

Once we have access to the template and view container, we can render the contents of the template based on some logic. We can manipulate elements in the DOM.

Above we use the set mySD input setter to check the condition and render the template if the condition is true.
The viewContainerRef.clear() function tells the view container not to render the elements. The createEmbeddedView embeds a template into the view container.

Here’s something for you to try out:

Can you create a custom structural directive that replicates the functionality of *ngFor?
How would you embed multiple templates into the view container?

(the answer is simpler than you think)…

Attribute Directives

The purpose of attribute directives is to change the appearance or behavior of elements in the DOM. Unlike structural directives, we aren’t trying to change the structure of the elements (or the position).
If you’re following along with the git repo, you can see the custom attribute directive we have created by entering git checkout attribute-directive.
The directive we have created allows you to strike through any element with a click. Here’s what it looks like.

We already spoke about the @Directive decorator and the selector in the metadata. Let’s break down the other pieces in this attribute directive.

ElementRef gives us access to the DOM’s element. We will use this to toggle the text-decoration property of the element.
Renderer basically allows us to render the changes we want to make to the element.

Since we want to change the behavior when the user clicks the element, we need a way to access events. For this, we use the @HostListener decorator.

We now have access to different events on the element which uses this directive.

In the code above, we listen for a click event and then toggle the line-through property of the element by calling the strike function.

The strike function simply uses the renderer to change the element style (based on the condition passed in the argument).

We just wrote our first custom attribute directive!

Conclusion – Which Directive Should We Use?

Let’s quickly go over the kinds of directives we discussed and their use cases –

1. Components (directives with templates)

Use these to build the UI elements that are the building blocks of the application. You can nest components within other components.

This could be a route in your application, a clock on a page, a button that submits a form.

2. Structural Directives

Use these when you want to change the DOM layout based on certain attributes or conditions.

In most cases, your layout requirements will be met the many structural directives within the Angular library.

3. Attribute Directives

Use these directives when you want to change the behavior or appearance of your components or HTML elements. You can make these directives respond to user interaction as well by using the @HostListener decorator.

Congratulations! You now know about the three different kinds of Angular 2 directives and how to use them in your next Angular 2 application.

Enjoy your directives!

P.S. Lifecycle hooks in directives

We can control the behavior of directives using lifecycle hooks as well. These pieces of code run based on the directive’s interaction with the entire app.
This means that we can change the behavior of our directive as and when Angular creates, changes and destroys them.
Since lifecycle hooks are beyond the scope of this article, we’ll let you explore them!