Directives are an important feature of AngularJS. They are usually markers on a DOM element that will tell the compiler the kind of behavior that should be attached to a certain DOM element. They are also used in order to transform the entire DOM element together with its children. Directives are what you will be using most often as you create your Angular.js applications.
AngularJS comes with a number of built-in directives that web developers can use freely, for instance ngClass, ngModel and ngBind, among others. It is also possible to create your own directives that can be used in Angular.js, which in turn gives you more control whenever you are creating applications.
Part of the reason that directives are essential in Angular.js include the fact they will give the user autonomy to add more to the grammar of the web, by use of HTML elements that can be used again, with classes as well as attributes. Directives can be very easy to create especially when it comes to the simple ones as we have seen in our last post on AngularJS. As you advance your skills in Angular.js, you will learn how to create more complex directives, which will give greater effects on your apps.
How to match directives
Angular.js HTML compiler is the one that determines when a certain directive will be used. An element will match a directive when that directive is part of the element’s declaration. Below is an example:
<input ng-model="foo">
In that example, it is true to say that the <input>element matches the directive ngModel.
Below are some more examples of elements that match their directives:
<input data-ng-model="foo"> <person>{{name}}</person>
In order to determine which elements match with which directives, Angular.js will normalize the tag and attribute name of that element. That is why directives have a case sensitive normalized name, for instance ngModel. But then again HTML is case sensitive, which leaves the directives in DOM with lower case forms. A dash attribute is then used on DOM elements.
Example: ng-model
Types of directives
$compile can be used to match directives on the basis of attributes, element names, class names and comments too. All the directives that have been provided by Angular.js have to match an attribute name, tag name, comments or even class names.
Creating a directive
Directives have to be registered on modules by an API used for registering directives module.directive API. The module-directive will take the directive name after it is normalized, then it will be followed by a factory function. The factory function in this case will be the one that will return the object with different options in order to give $compile an idea of the expected results of the directive after it has been matched.
The factory function will be used only once, only when the compiler will match the directive for the very first time. This is what is used: $injector.invoke. This makes the factory function injectable.
Scope Isolation
Scope in Angular.js is highly related to directives. It is in fact the part that makes directives a bit confusing for many new Angular.js users.
Naturally and by default, a scope will inherit from its parent scope. This is usually a problem if you are building a widget that will be used afterwards. Directives are not allowed to read or to write properties that are in the parent scope, which is why an isolated scope becomes a necessity. When you isolate a scope, you can easily control when your directives will have a state with other directives and controllers and how it will be done. This is a major requirement during application building.
An isolated scope is one that will not inherit from its parent scope. To understand these kinds of scopes, you will need to understand the following isolate scope building methods:
a) The attributes
You are able to bind a property of an isolated scope to that of a DOM. This is what results to a one way of binding data from the parent scope all the way to the isolated scope. If there is change in the parent scope, the isolated scope will have a reflection of that change but if the isolated scope changes, the parent scope is unaffected.
A @ symbol will be used in the scope property definition in the directive to achieve this. This is mainly a method used for reading an attribute.
Example:
directive('myComponent', function () { return { scope:{ isolatedAttributeFoo:'@attributeFoo', } }; })
b) Bindings
Binding works just the same way as attributes except for the fact that you will be using = symbol for this and not @ symbol.
This method is mainly used when you are creating a bi-directional two way binding.
Below is an example:
directive('myComponent', function () { return { scope:{ isolatedBindingFoo:'=bindingFoo', } }; })
To get a simple syntax, always ensure that the properties in your parents scope have the same name with those in the isolated scope
c) Expressions
When calling the expression on the parent scope from an isolated scope, you will use & symbol. It is basically the method you will use to make a call on something from a controller scope. Here is an example:
directive('myComponent', function () { return { scope:{ isolatedExpressionFoo:'&' } }; })
Effects of isolated scopes:
- It makes it possible and easy to add different data to the scope that is inside a directive, something that would have been impossible if the isolation was not made.
- It will protect your component from changing the state of your model except for those models that you will literally pass in. This gives you total control whenever you are creating an application.
You can always use the scope option to create isolated scopes whenever you are making components that you want to use throughout your application.
Understanding Directives and Scope isolation is important before you get started on Angular.js. They are some of the main features that you will need to use when building your applications and will have amazing effects.