Directives

Directives are what Angular uses to connect to the Document Object Model (DOM). This allows Angular to separate the concerns of what each part of the application should do. This means that a controller should never touch the DOM. A controller should only work through directives to change the DOM.

Normalization

When using directives, Angular must parse the DOM and figure out what directives apply to it. This is done by normalizing all the elements and tags. Normalization will remove any ";" "," " -", or" _". It will also remove x- and data- from the beginning of any attributes. For example, when looking for ngModel, all of the following will match:

  • x-ng:model
  • data-ng_model
  • ng-model
  • ng:model

Note

If you are concerned with HTML 5 validation, then you should use the data- normalization.

Scope

Scopes inside directives can become very confusing. We will look at a few examples of the different ways to use scope.

First up is just inheriting the scope. This means that the directive will use whatever value the variable has in the controller's scope. In this example, test will have to be set in the controller's scope:

firstModule.directive('firstTest', function () {
  return {
    template: 'This is the test directive. Test: {{test}}'
  };
});

@ binding

The next scope modification will be to isolate the scope. You can set the scope property of the returned Directive Definition Object (see the next section). What you use here will change how the scope is built. An @ symbol will read in the value as a one-way bind into the scope. An = symbol will create a two-way bind. Each of these can have the name of the attribute used after them.

For example, to bind one way to the attribute scope-test, use: @scopeTest. Here is an example that does that:

firstModule.directive('firstTest', function () {
  return {
    restrict: 'AE',
    scope: {
      test: '@scopeTest'
    },
    template: 'This is the test directive. Test: {{test}}'
  };
});

This can be used like this:

<div first-test scope-test="Scope Test Value"></div>

= binding

Here is the example using =. The controller will need to have a variable in scope to pass to the directive. Here is the directive:

firstModule.directive('firstTest', function () {
  return {
    restrict: 'AE',
    scope: {
      test: '='
    },
    template: 'This is the test directive. Test: {{test}}'
  };
});

The directive is then used like this:

<div first-test test="fromControllerScope"></div>

Notice that the attribute used to connect the scope was called test. This is because we only used =, instead of =nameOfVariable.

& binding

This is the final way is to pass a function in. This is done with &. When creating a directive with isolated scope, you run into a problem with letting the controller know when to take an action. For example, when a button is clicked, the & binding allows the controller to pass in the reference to a function and have the directive execute it.

Here is an example directive:

firstModule.directive('firstTest', function () {
  return {
    restrict: 'AE',
    scope: {
      testAction: '&'
    },
    template: '<button ng-click="testAction()">Action!</button>'
  };
});

The template now has a button that will call testAction when clicked. The testAction parameter that will execute is passed in from the controller and lives in the directive's scope.

Here is the DOM of this directive:

<div first-test test-action="functionFromController()"></div>

Another situation comes up where you will need to pass information from the directive to the controller, for example, the event object or a variable from the scope. Here is an example that shows how Angular makes the $event object available in functions.

Here is the directive:

firstModule.directive('firstTest', function () {
  return {
    restrict: 'AE',
    scope: {
      testAction: '&'
    },
    template: '<button>Action!</button>',
    link: function ($scope, element) {
      element.on('click', function (e) {
        $scope.$apply(function () {
          $scope.testAction({ $e: e, $fromDirective: 'From Directive' });
        });
      });
    }
  };
});

The key is the link property. This runs after compilation of the directive and is bound to the instance of the directive. This is important if you have a repeating directive. Next you listen for click using a jQuery-like API called JQLite. From here, we must call $apply because we are outside of Angular and it will not pick up any changes made here. Finally, we executed the expression that was passed in creating two variables, $e and $fromDirective, that will be available in the function in the controller.

Here is what the directive will look like in the DOM:

<div first-test test-action="functionFromController($e, $fromDirective)"></div>

The two variables, $e and $fromDirective, need to be called the same thing as you defined in the directive.

Modifying DOM

Angular makes very clear separation of concerns. This helps prevent hard-to-trace bugs from appearing. One of the separations is that controllers should not modify the DOM. Where does one modify the DOM then? In directives.

Directives are the only piece of your Angular application that should have any knowledge of what elements are in the DOM. When a DOM modification needs to be made, it should be the directive that does it.

Angular includes a jQuery-like library called jQLite. It has many of jQuery's DOM manipulation functions. If you know jQuery, you already know jQLite.

Here is a simple example of a directive that adds a div element when a button is clicked. The example uses jQLite's append function:

firstModule.directive('firstTest', function () {
  return {
    restrict: 'AE',
    scope: {
      testAction: '&'
    },
    template: '<button>Add a DIV!</button>',
    link: function ($scope, element) {
      element.on('click', function (e) {
        element.append('<div>I was added!</div>');
      });
    }
  };
});

Event binding

In an Angular application, only directives should be listening for DOM events, for example, the click event. This makes it very clear where the handlers reside.

Here is an example that binds to the click event of the element and logs to the console:

firstModule.directive('firstTest', function () {
  return {
    restrict: 'AE',
    scope: {
      testAction: '&'
    },
    template: '<button>Add a DIV!</button>',
    link: function ($scope, element) {
      element.on('click', function (e) {
        console.log(e);
      });
    }
  };
});

Additionally, directives can let a controller pass in a function and execute it when an event happens (see = binding). Finally, the directive can even pass parameters into the controller from the directive. A great example is the event object that is returned from the event (see & binding).

Directive definition object

The directive definition object is the object that tells Angular how to build a directive.

Here are the most used properties and a quick overview of what they do:

  • priority: A directive with a higher priority will be compiled first. This defaults to 0.
  • scope: See Directives, Scope section for a much more in depth overview.
  • controller: This can be confusing, but controller is used to share logic between directives. Another directive can share the code in the controller by using require and listing the name of the required directive. That directive's controller will be injected into the link function. The function will have the following definition: function($scope, $element, $attrs, $transclude).
  • require: A string of the directive that is required. Prepending ? will make this optional, ^ will search the element and parents throwing an error if not found, and ?^ will search the element and parents, but is optional. The function instance will be shared across directives.
  • restrict: This will restrict the ways you can define the directive in the DOM. Here are the options, with E and A being the most commonly used ones:
    • E: This stands for element
    • A: This stands for attribute and default
    • C: This stands for class
    • M: This stands for comment
  • template: HTML as a string or a function that returns a string that has the definition of function(element, attrs).
  • templateUrl: Loads the template from this URL.
  • link: This is where any DOM manipulations or listeners are put. This function will have this definition: function(scope, element, attrs, requiredController, transcludeFunction). If another directive is required, then its controller property would be the requiredController parameter.

Controller vs link

When to use the controller or link function can be very confusing when building directives. You should view the controller function as the interface that another directive can use. When a directive is required by another directive, the controller return value is injected into the link function. This will be the fourth parameter. The object is then accessible from link. The link function is used for any DOM manipulations or listeners.

Key directives

Here are some of the most often used directives.

ngApp

This is the root of your Angular application:

<element ng-app></element>

Parameters

  • The ng-app(string) attribute is the name of the default module.

Description

This will set the root element of the application. This can be put on any element, including the root HTML element.

This will automatically bootstrap Angular loading the module that is defined in ng-app.

ngModel

This binds data from the scope to elements:

<input ng-model [ng-required ng-minlength ng-maxlength ng-pattern ng-change ng-trim]></input>

Parameters

  • ng-model(string): This will be a variable in the scope
  • ng-required(boolean): This sets this input as required
  • ng-minlength(int): This sets the minimum length
  • ng-maxlength(int): This sets the maximum length
  • ng-pattern(string): This is the regular expression that the value must match
  • ng-change(expression): This is the Angular expression that will execute on value change
  • ng-trim(boolean): This decides whether or not to trim the value

Description

This is used to bind variables in the controller's scope to input elements (text, select, or textarea). This will be a two-way binding, so any changes in the variable will update all occurrences of it.

Here is a simple example with text input:

<input ng-model="test" type="text"/>
  {{test}}

ngDisabled

This can disable an element:

<input ng-disabled></input>

Parameters

  • If the ng-disabled(expression) attribute evaluates to true, the input will be disabled.

Description

This allows you to disable an input easily through code. The expression can bind to a scope variable or just evaluate what is in the expression.

Here is a simple example that disables a text input:

<input ng-disabled="true" type="text"/>

ngChecked

This can make an element checked:

<input ng-checked></input>

Parameters

  • The ng-checked(expression) attribute is the Angular expression that should evaluate to a JavaScript Boolean value.

Description

This is the Angular way to check or uncheck a checkbox based on something in the controller.

Here is an example:

<input ng-checked="true" type="checkbox"/>

ngClass

This sets the class of an element:

<element ng-class></element>

Parameters

  • The ng-class(expression) attribute can be a string, array, or an object map.

Description

When the expression is a string or array, then the value of the string or the values of the array will be applied as classes to the element. These can be tied to variables in the scope, of course.

Here is an example of using a string to set the class. Here is the style that will be applied:

.double { font-size: 2em; }

Here is the code to apply it:

<div ng-class="classString">Text</div>
<input type="text" ng-model="classString" />

The class is tied to the value of the classString variable. The input is bound so that any change will update the class on div. Once you type in double, it will apply the style.

Here is an example using an object map. The object's property name is the class that will be applied and the value must be true. Here is a similar example utilizing the same class:

<div ng-class="{double: classString}">Text</div>
<input type="text" ng-model="classString" />

You will notice that once you type anything into the input, the class will be applied. This is because a non-blank string will be true. You can use this to apply as many classes as needed using more properties.

ngClassOdd and ngClassEvent

These set the class of an odd or even element, respectively:

<element ng-class-odd></element>
<element ng-class-even></element>

Parameters

  • The ng-class-odd or ng-class-even(expression) attributes must evaluate to a string or an array of strings that will become the class(es) for the element.

Description

These two directives are related and can even be applied to the same element. If a repeated element is odd, then ng-class-odd will evaluate and the same is true for ng-class-even.

Here is an example that will make every odd element twice the size and every even element half the size. Here are the styles:

.odd { font-size: 2em; }
.even { font-size: .5em; }

Here are the elements. The ul attribute creates the data to be repeated, and each span parameter statically sets the class to either odd or even. You can use variables in scope as well:

<ul ng-init="numbers=[1,2,3,4]">
  <li ng-repeat="number in numbers">
  <span ng-class-even="'even'" ng-class-odd="'odd'">{{number}}</span>
  </li>
</ul>

ngRepeat

This is a template that can be repeated:

<element ng-repeat></element>

Parameters

  • The ng-repeat(repeat_expression) attribute is similar to an expression, but it has a few syntax differences. Go to the description for the full explanation.

Description

Many times you will have data that has a similar template, but changes for each row of data. This is where ng-repeat comes in. The ng-repeat function will repeat the HTML that you have for each item in the repeat expression.

The repeat expression is an expression that tells ng-repeat what items are going to be looped over. Here is a rundown of some expressions:

  • item in collection: This is the classic foreach statement. It will loop over each item in a collection (an array, for example). The item parameter will be available inside the template.
  • (key, value) in collection: If your data is in an object and you want to be able to associate the name of the property to the value, then you will need to do use this.
  • item in collection track by grouping: This allows for grouping. The grouping will only give you one item for each unique value of grouping.
  • repeat expression | filter: You can filter any of these expressions to give you a subset of the data.

Here is an example using an unordered list. Here is the controller:

firstModule.controller('SimpleController', ['$scope', function ($scope) { 
  $scope.items = [{id: 1, name: 'First' }, {id: 2, name: 'Second'}];
}]);

Here is the HTML for the controller:

<div ng-controller="SimpleController">
  <ul>
    <li ng-repeat="item in items track by item.id">
      ID: {{item.id}}
      Name: {{item.name}}
    </li>
  </ul>
</div>

ngShow and ngHide

These can show or hide elements, respectively:

<element ng-show></element>
<element ng-hide></element>

Parameters

  • The ng-show or ng-hide(expression) attributes will be evaluated to true or false, and the element will either by shown or hidden.

Description

These directives allow you to show or hide content based on the data in the scope.

Here is an example that uses a counter to show or hide elements. You can use ng-hide and use the opposite logic. Here is the controller:

firstModule.controller('SimpleController', ['$scope', function ($scope) {
  $scope.count = 0;
  $scope.increase = function () { $scope.count++; };
}]);

Next is the HTML:

<div ng-controller="SimpleController">
  <div ng-show="count == 0">Count is zero: {{count}}</div>
  <div ng-show="count > 0">Count is greater than zero: {{count}}</div>
  <button ng-click="increase()">Increase Count</button>
</div>

ngSwitch

This creates a switch statement:

<element ng-switch>
<element ng-switch-when></element>
<element ng-switch-default></element>
</element>

Parameters

  • ng-switch(expression): This is an expression that returns a value. This value will be used when evaluating ng-switch-when.
  • ng-switch-when(expression): When the value matches this expression, then this element will be visible.
  • ng-switch-default: This element will show when ng-switch-when does not match.

Description

This directive works much like the JavaScript switch statement. Different cases are tested against, and the one that matches is used. If none of the cases match, then a default element is used.

Here is an example that jumps between even and odd. Here is the controller:

firstModule.controller('SimpleController', ['$scope', function ($scope) {
  $scope.count = 0;
  $scope.increase = function () { $scope.count++; };
}]);

Then comes the HTML:

<div ng-controller="SimpleController">
  <div ng-switch="count % 2">
    <div ng-switch-when="0">Count is Even: {{count}}</div>
    <div ng-switch-when="1">Count is Odd: {{count}}</div>
  </div>
  <button ng-click="increase()">Increase Count</button>
</div>

ngClick

This is used to define the click handler:

<element ng-click></element>

Parameters

  • The ng-click(expression) attribute is what will be evaluated when the element is clicked. A function can be used, and the event object is available using the function($event) function definition. Any other variables in scope can be passed as well, for example, $indexin a repeater.

Description

This directive allows you to run JavaScript on the click of an element. Usually, this is used with a function that is in the scope.

Here is an example that will increment a scope variable. First, here are the controller's scope variables:

$scope.counter = 0;
$scope.functionFromController = function (e) { $scope.counter++; };

Next, this is the element with the ng-click directive. In this example, you do not use the event object, but it demonstrates how to get it to the controller function:

<button ng-click="functionFromController($event)">Click Me!</button>
{{counter}}

ngDblclick

This is used to define the double-click handler:

<element ng-dblclick></element>

Parameters

  • The ng-dblclick(expression) function, a function can be used and the event object is available using the function($event) function definition. Any other variables in scope can be passed as well, for example, $index in a repeater.

Description

This directive is very similar to ngClick. When the element is double-clicked, the expression will be evaluated.

This is an example of a div that will increment a counter when double-clicked. Here are the controller's variables:

$scope.counter = 0;
$scope.functionFromController = function (e) { $scope.counter++; };

Here is the element and directive:

<div ng-dblclick="functionFromController($event)">Double Click Me!</div>
{{counter}}

ngMousedown, ngMouseup, ngMouseover, ngMouseenter, and ngMouseleave

These are used to define the mouse event handlers:

<element ng-mousedown></element>
<element ng-mouseup></element>
<element ng-mouseover></element>
<element ng-mouseenter></element>
<element ng-mouseleave></element>

Parameters

  • In the ng-mouse*(expression) function, a statement or function can be used, and the event object is available using the function($event) function definition. Any other variables in the scope can be passed as well, for example, $index in a repeater.

Description

These are grouped together as they are all related. When the mouse takes the action (down, up, over, enter, or leave), the expression will be evaluated.

This example is a little crazy, but it demonstrates how to use these events. Here is the relevant portion of the controller:

$scope.counter = 0;
$scope.functionFromController = function (e) { $scope.counter++; };

Here are the directives:

<div ng-mousedown="functionFromController($event)" ng-mouseup="functionFromController($event)"
  ng-mouseenter="functionFromController($event)" ng-mouseleave="functionFromController($event)"
  ng-mouseover="functionFromController($event)">Mouse Over Me!</div>
{{counter}}

ngMousemove

This is used to define the mouse move handler:

<element ng-mousemove</element>

Parameters

  • In the ng-mousemove(expression) function, a statement or function can be used, and the event object is available using the function($event) function definition. Any other variables in the scope can be passed as well, for example, $index in a repeater.

Description

This fires when the mouse moves. Unless the directive is on the entire page, the event will be limited to only the element it is applied to.

Here is an example that will display the mouse's x and y coordinates. Here are the relevant scope variables:

$scope.x = 0;
$scope.y = 0;
$scope.functionFromController = function (e) {
  $scope.x = e.pageX;
  $scope.y = e.pageY;
};

Then comes the directive:

<div ng-mousemove="functionFromController($event)">Move the mouse to see the x and y coordinates!</div>
{{x}}
{{y}}

ngKeydown, ngKeyup, and ngKeypress

These are used to define the key press handlers:

<element ng-keydown></element>
<element ng-keyup></element>
<element ng-keypress></element>

Parameters

  • In the ng-key*(expression) function, a statement or function can be used, and the event object is available using the function($event) function definition. Any other variables in the scope can be passed as well, for example, $index in a repeater.

Description

These will fire when the key is pressed or released.

Here is an example that will retrieve the key code from the key that was pressed down. Here are the relevant scope variables:

$scope.keyCode = 0;
$scope.functionFromController = function (e) {
  $scope.keyCode = e.keyCode;
};

Next comes the directive:

<input type="text" ng-keydown="functionFromController($event)"/>
Which key: {{keyCode}}

ngSubmit

These are used to define the submit handler:

<form ng-submit></form>

Parameters

  • In the ng-submit(expression) function, a statement or function can be used, and the event object is available using the function($event) function definition. Any other variables in the scope can be passed as well, for example, $index in a repeater.

Description

This directive is used to capture the submit event of a form. If the form does not have an action attribute, then this will prevent the form from reloading the current page.

Here is a simple example that logs the event object to console on submit. Here is the directive:

<form ng-submit="functionFromController($event)"><input type="submit" id="submit" value="Submit" /></form>

Next comes the controller code:

$scope.functionFromController = function (e) {
  console.log(e);
};

ngFocus and ngBlur

These are used to define the focus and blur handlers, respectively:

<input, select, textarea, a, window ng-focus></input>
<input, select, textarea, a, window ng-blurs></input>

Parameters

  • In the ng-focus(expression) function, a statement or function can be used, and the event object is available using the function($event) function definition. Any other variables in the scope can be passed as well, for example, $index in a repeater.

Description

The ngFocus handler will fire when the element gains focus, and ngBlur will fire when it loses focus. Here is an example with a text input that logs the event to console:

<input type="text" ng-focus="functionFromController($event)"/>

Here is the controller code:

$scope.functionFromController = function (e) {
  console.log(e);
};

ngCopy, ngCut, and ngPaste

<element ng-copy></element>
<element ng-cut></element>
<element ng-paste></element>

Parameters

  • ng-copy, ng-cut, or ng-paste(expression): A statement or function can be used, and the event object is available using the function($event) function definition. Any other variables in the scope can be passed as well, for example, $index in a repeater.

Description

These are the events that will be fired when text is either cut, copied, or pasted. Here is an example that uses all three:

<input type="text" ng-cut="functionFromController($event)" ng-copy="functionFromController($event)" ng-paste="functionFromController($event)" />

Here is the controller code:

$scope.functionFromController = function (e) {
  console.log(e);
};
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.130.199