Tuesday, 27 September 2016

Custom Directive Isolated Scope

Javascript Code:

var app = angular.module("myApp",[]);

app.controller("Ctrl1",function($scope){
    $scope.name = "Krishna";
    $scope.reverseName = function(){
        $scope.name = $scope.name.split('').reverse().join('');
    };
});
app.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {},
        template: "<div>Your name is : {{name}}</div>"+
        "Change your name : <input type='text' ng-model='name'/>"
    };
});

HTML:
<div ng-app="myApp">
     <div ng-controller="Ctrl1">
        <h2 ng-click="reverseName()">Hey {{name}}, Click me to reverse your name</h2>
        <div my-directive class='directive'></div>
    </div>
</div>

We just created a directive with an isolated scope. Notice, even the parent scope has a name “Krishna”, the textbox inside directive is blank. This is because of the new Isolated scope doesn’t know anything about its parent scope.

But, can we pass some values from the parent scope to the directives now?

Yes ! Not only that, we might need to handle situations like invoking callbacks in parent scope, two-way binding between parent & directives scope ..etc

To access any parent scope data, we need to pass that to our directive explicitly. This is achieved by setting properties on the scope object in the DDO. Imagine these properties as interfaces of the directive to communicate with outside scope. Another important thing is that, these properties also MUST be set as the attributes of the directive html element.

Lets go in deep .......

Javascript code

 var app = angular.module("myApp", []);
 app.controller("MainCtrl", function( $scope ){
    $scope.name = "Krishna";
    $scope.color = "#333333";
    $scope.reverseName = function(){
     $scope.name = $scope.name.split("").reverse().join("");
    };
    $scope.randomColor = function(){
        $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
    };
});
myApp.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {
            name: "@",
            color: "=",
            reverse: "&"
        },
        template: [
            "<div class='line'>",
            "Name : <strong></strong>;  Change name:<input type='text' ng-model='name' /><br/>",
            "</div><div class='line'>",
            "Color : <strong style='color:'></strong>;  Change color:<input type='text' ng-model='color' /><br/></div>",
            "<br/><input type='button' ng-click='reverse()' value='Reverse Name'/>"
        ].join("")  
    };
});

It’s clear that, the controller MainCtrl creates the parent scope. This parent scope has following properties and methods -

  • name = "Krishna"
  • color =  "#333333"
  • reverseName = function for reversing the name
  • randomColor = function for generating random color code

Similarly, we’ve created our directive in Isolated scope by setting an object literal in the DDO. Now our scope object has some properties:

scope: {
        name: "@",
        color: "=",
        reverse: "&"
    }

We can see the scope properties are used in directive scope. Mostly the directive’s templates and link function are going to consume the scope properties. The behaviour of these properties again depends on their values –– also known as Prefixes –– provided. 

These Prefixes are used to bind the parent scope’s methods and properties to the directive scope. All these prefixes receives data from the attributes of the directive element.

There’re 3 types of prefixes AngularJS provides -

1. "@"   (  Text binding / one-way binding )
2. "="   ( Direct model binding / two-way binding )
3. "&"   ( Behaviour binding / Method binding  )


HTML Code:

<div my-directive 
  class="directive"
  name="{{name}}" 
  reverse="reverseName()" 
  color="color" >
</div>

When the directive encounters a prefix in the scope property, it will look for an attribute ( with same property name ) on directive’s html element. However, we can provide a different mapping between property and attributes. This is done by giving a separate attribute name after the prefix. Look at below code.
scope : {
    name: "@"
}

The above will be mapped to an attribute “name” in the directive. Now let’s see what happens if we change the code like below:

scope : {
    name: "@parentName"
}

At this time, the name property will be looking for an attribute “parent-name” in the html element to get its value. Simply, any string after the Prefixes should match the attribute name.

  • The “@” prefix is a one-way binding between the directive scope and parent scope. It always expects the mapped attribute to be an expression. This is very important; because to make the “@” prefix work, we need to wrap the attribute value inside {{}}. Since “@” is creating a one-way binding between the parent and directive scope, any changes made in the parent scope will reflect inside the directive scope, but not the other way. “@” prefix is really useful when our directive needs to be initialised with some data from parent scope.                        
  • Secondly we have the “=” prefix. It creates a two-way binding between the parent and directive scope. The most important point about “=” prefix is, it’ll always expect the attribute value to be the model name. That means you cannot provide an expression as the value of attribute mapped to “=” prefix. This is useful, when any of our directive scope property to be same as the parent scope property.                                                                           
  • Finally, we’re going to talk about the last prefix. The “&” prefix is also known as a "Method Binding". This is used to bind any methods from the parent scope to the directive scope. This will be particularly useful when our directive needs to execute any callbacks in the parent scope. Look at the code to see how attribute value for the “&” prefix to be set.                                              
That’s it ! 

No comments:

Post a Comment

Monads in Scala

Monads belongs to Advance Scala   concepts. It  is not a class or a trait; it is a concept. It is an object which covers other object. A Mon...