#TECH

Scope in Custom Directives (AngularJS)

Scope in Custom Directives

This blog’s main purpose is to ease the understanding of the $scope in the custom directives. While creating custom directives we have to apply different types of functionalities, so for that we must know about the $scope behavior in the directives.

$scope has a very important role in AngularJS, it works as a mediator (or like a glue) between the logic & view in an Angular application. Now if we talk about the custom directives, then first question which arises is-

Why do we need custom directives?

The answer is-

“In any application if we want some specific functionality and we want to reuse that in whole application module, then for this we need to develop a set of code. Angular calls it directives.”

I am not going to discuss so much about custom directives basics here. In this blog I am just focusing on use of $scope into directives.

So, when we create a custom directive it has a default scope, which is the parent scope (the controller’s scope from where the directive is called). This behavior is by default, until and unless we do not set the scope.

As we know that whenever we define a directive, there is a “directive definition object” (DDO), in which we set some parameters like- restrict, template, require, scope etc.

In this blog I will talk about the scope properties, they are  false, true, {}.

Let’s discuss them one by one.

Scope : false (Shared Scope)

In layman language false is assumed as no, so if the scope is set to false, then it means use parent scope in the directive and do not create a new scope for the directive itself. It just uses the scope of respective controller. So let us suppose if we have a controller named “homeController” and a directive “printName”, then in printName directive we will get parent scope by default and any change in scope values, either child or parent, will reflect in both.

Example:

Code Snippet
  1. var app = angular.module(“blogDemo”, []);
  2. app.controller(“sharedController”, function ($scope) {
  3.     $scope.name = “rock”;
  4. });
  5. app.directive(“sharedDirective”, function () {
  6.     return {
  7.         restrict: “EA”,
  8.         scope: false,
  9.         template: “<div>directive scope value : {{name}}</div>” +
  10.         “Change directive scope value : <input type=’text’ ng-model=’name’ />”
  11.     };
  12. });

 

//view (html)

<div ng-app=”blogDemo”>

      <div ng-controller=”sharedController“>

           <h2>parent scope value {{name}} </h2>

           <div shared-directive ></div>

       </div>

</div>

In this example, we can see whenever the value of parent scope changes, it will reflect in the directive scope also, because they both are sharing the same scope object.

Scope : true (Inherited Scope)

Using this property, the directive will create a new scope for itself. And inherit it from parent scope. If we do any changes to the controller scope it will reflect on directive scope, but it won’t work the other way around. This is because both of them use their own copies of scope object.

Example:

Code Snippet
  1. //module, controller, directive
  2. var app = angular.module(“blogDemo”,[]);
  3. app.controller(“inheritedController”,function($scope){
  4.     $scope.orgName = “Quovantis Parent”;
  5. });
  6. app.directive(“inheritedDirective”, function(){
  7.     return {
  8.         restrict: “EA”,
  9.         scope: true,
  10.         template: “<div>my organisation name is : {{orgName}}</div> type for change name : <input type=’text’ ng-model=’orgName’ />”
  11.     };
  12. });

 

//view (html)

<div ng-app=”blogDemo”>

       <div ng-controller=”inheritedController“>

            <h2>parent scope value {{orgName}} </h2>

            <div inherited-directive ></div>

        </div>

</div>

In this example when the first time directive loads, the screen will show the value of parent scope. But when we will change the value from text box. Then this will only change into child scope only. Means no change in parent scope.

Scope : {} (Isolated Scope)

One of the important features, its called isolated scope. Here too the directive will create a new scope object but it is not inherited by the parent scope, so now this scope doesn’t know anything about the parent scope.

But the question arises, if we do not have the link from parent scope then how can we get the values from it, and how can we modify it ?

The answer is- set the objects property into DDO, but for this it is necessary to set on attributes into the directive.

In isolated scope we use three prefixes which helps to bind the property or methods from the controller (parent scope) to directive (isolated scope). Lets understand how this works.

Whenever a directive finds any prefixes in its scope property in DDO, it checks it in directive declaration (in html page where the directive is called) with attribute declared on this element. We can also change the name by giving a separate attribute name after any of the prefixes.

These are @, =, &

‘@’ : One way binding

One way binding means a parent sending anything to the directive scope through the attribute, gets reflected in the directive. But if any change in the directive happens it will not reflect in parent. The @ is used to pass string values.

Example:

Code Snippet
  1. //module
  2. var app = angular.module(‘quovantisBlog’, []);
  3. //controller
  4. app.controller(‘OneWayController’, [‘$scope’, function ($scope) {
  5.     $scope.student = {
  6.         name: ‘Rohit’,
  7.         class: ‘MCA’,
  8.         Address: ‘New Delhi’    
  9.     };
  10. }]);
  11. // directive
  12. app.directive(‘oneWayDirective’, function () {
  13.     return {
  14.         scope: {
  15.             name: ‘@’
  16.         },
  17.         template: ‘Student  Name: {{ name }}’
  18.     };
  19. });

 

//view (html)
<one-way-directive name=”{{ student.name }}”></one-way-directive>
or
<one-way-directive studName=”{{ student.name }}”></one-way-directive>
then directive would be with a change in scope property.

Code Snippet
  1. app.directive(‘oneWayDirective’, function () {
  2.     return {
  3.         scope: {
  4.             name: ‘@studName’
  5.         },
  6.         template: ‘Student Name: {{ name }}’
  7.     };
  8. });

 

‘=’ : Two way binding

This is called two way binding, because the parent scope will also reflect to directive scope vice-versa.

It is used for passing object to the directive instead of string. This object could be changed from both sides, from parent or from directive. That is why it is called two-way.

Example:

Code Snippet
  1. //module
  2. var blogDemo = angular.module(‘myApp’,[]);
  3. //directive
  4. blogDemo.directive(‘twoWayDirective’, function() {
  5.     return {
  6.         restrict: ‘EA’,
  7.         scope: { obj: “=”},
  8.         template: ‘<div>Welcome, {{obj.fname + obj.lname}}!</div>’
  9. };
  10. });
  11. //controller
  12. blogDemo.controller(‘blogController’, function ($scope) {
  13. $scope.obj = { fname: “shubh”, lname: “raj” };
  14. });

 

//view (html)

<div ng-controller=”blogController”>

     <two-way-directive obj=”obj”></two-way-directive>

</div>

‘&’ : Method binding

Used to bind any parent’s method to directive scope. Whenever we want to call the parent methods from the directive we can use this. It is used to call external (outside of current scope) functions. Overall “&” is used to pass data as a function or method.

Example:

Code Snippet
  1. //module
  2. var blogDemo = angular.module(‘myApp’,[]);
  3. //directive
  4. blogDemo.directive(‘methodDirective’, function() {
  5.     return {
  6.         scope: {
  7.             studData: ‘=’,
  8.             swap: ‘&’
  9.         },
  10.         template: ‘<div>the changed names are, {{obj.fname + obj.lname}}!</div>’+
  11.             ‘<button id=”btn1” ng-click=”swap()”>Click here to Swap student Data</button>’
  12.     };
  13. });
  14. //controller
  15. blogDemo.controller(‘blogController’, function ($scope) {
  16.     $scope.studData = { fname: “shubh”, lname: “raj” };
  17.     $scope.swapData = function () {
  18.         $scope.customer = {
  19.             fname: ‘Raj’,
  20.             lname: ‘kumar’
  21.         };
  22.     };
  23. });

 

//view (html)

<div ng-controller=”blogController”>

        <method-directive studData=”studData” swap=”swapData()”></method-directive>

</div>

In this example the directive creates a property inside its local scope, that is swapData. We can also understand swap as an alias for swapData. So we pass a method to ‘&’ which is then invoked by the directive whenever required.

Summarizing, Shared scope (sharing the same scope and data, can not pass the data explicitly), Inherited scope (parent scope values can be fetched into child but child means directive scope will not effect parent), Isolated scope (both controller & directive do not share the scope & data, we can explicitly pass the data using some parameters that is @, & ,= ).