Custom Directives

Custom Directives

What are they?

  • A mechanism to create custom HTML elements
     
  • Similar to 'partials' but with the additional power of their own controller
     
  • Can also be used like ng-bind to add specific functionality to any existing html element

Create a Directive

angular.module('SimpleDirectiveApp').directive('simpleCustomer', function() {
    return {
      template: 'Name: {{customer.name}} Address: {{customer.address}} '
    };
  });

In the simplest form you simply register a directive on your application:

In this case, customer must be available in the $scope of the controller that the directive lives in.

Create a Directive

<simple-customer ng-repeat="customer in customers"></simple-customer>

Including the directive in your HTML:

And for clarity, the controller:

angular.module('SimpleDirectiveApp', [])
  .controller('MainController', function($scope) {
    $scope.customers = [
    {
      name: 'Naomi',
      address: '1600 Amphitheatre'
    },
    {
    	name: 'Tyler',
    	address: '1875 Texas Street'
    },
    {
    	name: 'Cookie Monster',
    	address: '1234 Cookie Street'
    }
    ]
  });

Create a Directive

<simple-customer ng-repeat="customer in customers"></simple-customer>

Angular turns our <simple-customer> tag into the template

angular.module('SimpleDirectiveApp').directive('simpleCustomer', function() {
    return {
      template: 'Name: {{customer.name}} Address: {{customer.address}} '
    };
  });

+

=

<simple-customer ng-repeat="customer in customers">
   Name: {{customer.name}} Address: {{customer.address}}
</simple-customer>

Use an HTML template

Directives support the use of HTML files that act as partials

angular.module('SimpleDirectiveApp').directive('templateCustomer', function() {
    return {
      templateUrl: '/templates/customerTemplate.html'
    };
  });

customerTemplate.html

<div>
  <h2>{{customer.name}}</h2>
  <p>{{customer.address}}</p>
</div>
<hr>

Use an HTML template

Using <template-customer>

<div ng-repeat="customer in customers>
  <h2>{{customer.name}}</h2>
  <p>{{customer.address}}</p>
</div>
<hr>
<template-customer ng-repeat="customer in customers"></template-customer>

Which becomes

A Note on $scopes

  • The previous two examples rely on the $scope of the controller in which they are defined -- which is not ideal
     
  • We can use the link function, provided by Angular, to give directives a unique scope

Isolate Scope

angular.module('SimpleDirectiveApp').directive('isolateScopeCustomer', function() {
    return {
  	scope: {
  	   customerValues: '=customerValues',
      },
      templateUrl: '/templates/isolateScopeTemplate.html',
      link: function(scope, element, attrs) {
      	scope.clickCount = 0;
      	
      	scope.handleClick = function(){
      		scope.clickCount += 1;
      	}
      }
    };
  });

scope defines how the directive receives information from the view. Note in the html customer-values="customer"

<isolate-scope-customer ng-repeat="customer in customers" customer-values="customer">
</isolate-scope-directive>

Isolate Scope

angular.module('SimpleDirectiveApp').directive('isolateScopeCustomer', function() {
    return {
  	scope: {
  	   customerValues: '=customerValues',
      },
      templateUrl: '/templates/isolateScopeTemplate.html',
      link: function(scope, element, attrs) {
      	scope.clickCount = 0;
      	
      	scope.handleClick = function(){
      		scope.clickCount += 1;
      	}
      }
    };
  });

Note that we still have a templateUrl

<div ng-click="handleClick()">
  <h2>{{customerValues.name}}</h2>
  <p>{{customerValues.address}}</p>
  <p>{{clickCount}}</p>
</div>
<hr>

isolateScopeTemplate.html

Isolate Scope

angular.module('SimpleDirectiveApp').directive('isolateScopeCustomer', function() {
    return {
  	scope: {
  	   customerValues: '=customerValues',
      },
      templateUrl: '/templates/isolateScopeTemplate.html',
      link: function(scope) {
      	scope.clickCount = 0;
      	
      	scope.handleClick = function(){
      		scope.clickCount += 1;
      	}
      }
    };
  });

The link function provides the scope for this directive. We create a clickCount and a function in the directives "isolate scope"

Additional Functionality

Sometimes, we don't want to create a custom tag, but we want to add custom functionality to any existing tag.

 

Directives are good for this too.

angular.module('DraggableApp', [])
.directive('myDraggable', ['$document', function($document) {
  return {
    link: function(scope, element, attr) {
      var startX = 0, startY = 0, x = 0, y = 0;

      element.css({
       position: 'relative',
       border: '1px solid red',
       backgroundColor: 'lightgrey',
       cursor: 'pointer'
      });

      element.on('mousedown', function(event) {
        // Prevent default dragging of selected content
        event.preventDefault();
        startX = event.pageX - x;
        startY = event.pageY - y;
        $document.on('mousemove', mousemove);
        $document.on('mouseup', mouseup);
      });

      function mousemove(event) {
        y = event.pageY - startY;
        x = event.pageX - startX;
        element.css({
          top: y + 'px',
          left:  x + 'px'
        });
      }

      function mouseup() {
        $document.off('mousemove', mousemove);
        $document.off('mouseup', mouseup);
      }
    }
  };
}]);

The examples in these slides are available here

https://github.com/gSchool/angular-curriculum/tree/master/Unit-2/examples/directive-examples

Questions?

Directives

By Tyler Bettilyon

Directives

  • 1,348