7 min read

(For more resources related to this topic, see here.)

What makes a directive a directive

Angular directives have several distinguishing features, but for the sake of simplicity we’ll focus on just three in this article. In contrast to most plugins or other forms of drop-in functionality, directives are declarative, data driven, and conversational.

Directives are declarative

If you’ve done any JavaScript development before, you’ve almost certainly used jQuery (or perhaps Prototype), and likely one of the thousands of plugins available for it. Perhaps you’ve even written your own such plugin. In either case, you probably have a decent understanding of the flow required to integrate it. They all look something like the following code:

$(document).ready(function() {
$('#myElement').myPlugin({pluginOpts});
});

In short, we’re finding the DOM element matching #myElement, then applying our jQuery plugin to it. These frameworks are built from the ground up on the principle of DOM manipulation. In contrast, Angular directives are declarative, meaning we write them into the HTML elements themselves. Declarative programming means that instead of telling an object how to behave (imperative programming), we describe what an object is. So, where in jQuery we might grab an element and apply certain properties or behaviors to it, with Angular we label that element as a type of directive, and, elsewhere, maintain code that defines what properties and behaviors make up that type of object:

<html>
<body>
<div id="myElement" my-awesome-directive></div>
</body>
</html>

At a first glance, this may seem rather pedantic, merely a difference in styles, but as we begin to make our applications more complex, this approach serves to streamline many of the usual development headaches.

In a more fully developed application, our messages would likely be interactive, and in addition to growing or shrinking during the course of the user’s visit, we’d want them to be able to reply to some or retweet themselves. If we were to implement this with a DOM manipulation library (such as jQuery or Prototype), that would require rebuilding the HTML with each change (assuming you want it sorted, just using .append() won’t be enough), and then rebinding to each of the appropriate elements to allow the various interactions.

In contrast, if we use Angular directives, this all becomes much simpler. As before, we use the ng-repeat directive to watch our list and handle the iterated display of tweets, so any changes to our scoped array will automatically be reflected within the DOM. Additionally, we can create a simple tweet directive to handle the messaging interactions, starting with the following basic definition. Don’t worry right now about the specific syntax of creating a directive; for now just take a look at the overall flow in the following code:

angular.module('myApp', [])
.directive('tweet', ['api', function (api) {
return function ($scope, $element, $attributes) {
$scope.retweet = function () {
api.retweet($scope.tweet);// Each scope inherits from it's
parent, so we still have access to the full tweet object of {
author : '…', text : '…' }
};
$scope.reply = function () {
api.replyTo($scope.tweet);
};
}
}]);

For now just know that we’re getting an instance of our Twitter API connection and passing it into the directive in the variable api, then using that to handle the replies and retweets. Our HTML for each message now looks like the following code:

<p ng-repeat="tweet in tweets" tweet>
<!-- ng-click allows us to bind a click event to a function on the
$scope object -->
@{{tweet.author}}: {{tweet.text}}
<span ng-click="retweet()">RT</span> |
<span ng-click="reply()">Reply</span>
</p>

By adding the tweet attribute to the paragraph tag, we tell Angular that this element should use the tweet directive, which gives us access to the published methods, as well as anything else we later decide to attach to the $scope object.

Directives in Angular can be declared in multiple ways, including classes and comments, though attributes are the most common.

Scoping within directives is simultaneously one of the most powerful and most complicated features within Angular, but for now it’s enough to know that every property and function we attach to the scope is accessible to us within the HTML declarations.

Directives are data driven

Angular directives are built from the ground up with this philosophy. The scope and attribute objects accessible to each directive form the skeleton around which the rest of a directive is built and can be monitored for changes both within the DOM as well as the rest of your JavaScript code.

What this means for developers is that we no longer have to constantly poll for changes, or ensure that every data change that might have an impact elsewhere within our application is properly broadcast. Instead, the scope object handles all data changes for us, and because directives are declarative as well, that data is already connected to the elements of the view that need to update when the data changes. There’s a proposal for ECMAScript 6 to support this kind of data watching natively with Object.observe(), but until that is implemented and fully supported, Angular’s scope provides the much needed intermediary.

Directives are conversational

Modular coding emphasizes the use of messages to communicate between separate building blocks within an application. You’re likely familiar with DOM events, used by many plugins to broadcast internal changes (for example, save, initialized, and so on) and subscribe to external events (for example, click, focus, and so on). Angular directives have access to all those events as well (the $element variable you saw earlier is actually a jQuery wrapped DOM element), but $scope also provides an additional messaging system that functions only along the scope tree. The $emit and $broadcast methods serve to send messages up and down the scope tree respectively, and like DOM events, allow directives to subscribe to changes or events within other parts of the application, while still remaining modular and uncoupled from the specific logic used to implement those changes.

If you don’t have jQuery included in your application, Angular wraps the element in jqLite, which is a lightweight wrapper that provides the same basic methods.

Additionally, when you add in the use of Angular services, directives gain an even greater vocabulary. Services, among many other things, allow you to share specific pieces of data between the different pieces of your application, such as a collection of user preferences or utility mapping item codes to their names. Between this shared data and the messaging methods, separate directives are able to communicate fully with each other without requiring a retooling of their internal architecture.

Directives are everything you’ve dreamed about

Ok, that might be a bit of hyperbole, but you’ve probably noticed by now that the benefits outlined so far here are exactly in line with the best practices. One of the most common criticisms of Angular is that it’s relatively new (especially compared to frameworks such as Backbone and Ember). In contrast, however, I consider that to be one of its greatest assets. Older frameworks all defined themselves largely before there was a consensus on how frontend web applications should be developed. Angular, on the other hand, has had the advantage of being defined after many of the existing best practices had been established, and in my opinion provides the cleanest interface between an application’s data and its display.

As we’ve seen already, directives are essentially data driven modules. They allow developers to easily create a packageable feature that declaratively attaches to an element, molds to fit the data at its disposal, and communicates with the other directives around it to ensure coordinated functionality without disruption of existing features.

Summary

In this article, we learned about what attributes define directives and why they’re best suited for frontend development, as well as what makes them different from the JavaScript techniques and packages you’ve likely used before. I realize that’s a bold statement, and likely one that you don’t fully believe yet.

Resources for Article:


Further resources on this subject:


LEAVE A REPLY

Please enter your comment!
Please enter your name here