AngularJS Directive Scope Attribute Binding – Isolate Scope

In this blog post we will see how scope work with directives, how directive inherits scope from controller and what are the best ways of doing this.

What is Scope Binding in a Directive

Lets take a case of directive, where we need to print data from a controller scope.
The a very simple example would be as below

            var app = angular.module('app', []);
            app.controller('ctrl', function ($scope) {
                $scope.name = 'Manish';
            });
            app.directive('mySon', function () {
                return {
                    restrict: 'E',
                    template: '<div>My Name is {{name}}</div>'
                };
            });
       <body ng-app="app">
        <div ng-controller="ctrl">
            <my-son></my-son>
        </div>
    </body>

In the above example, we simply passing a scope variable from controller to directive. Due to auto scope inheritance, the scope automatically passes to the directive.
The major drawback of this method is, for each time we use the directive we need to make a separate controller.
Suppose we have another another name which we won’t to print, we cannot do it without making another controller. Our new code would be something like this

            var app = angular.module('app', []);
            app.controller('ctrl', function ($scope) {
                $scope.name = 'Manish';
            });
            app.controller('ctrl1', function ($scope) {
                $scope.name = 'Prakash';
            });
            app.directive('mySon', function () {
                return {
                    restrict: 'E',
                    template: '<div>My Name is {{name}}</div>'
                };
            });
<body ng-app="app">
        <div ng-controller="ctrl">
            <my-son></my-son>
        </div>
        <div ng-controller="ctrl1">
            <my-son></my-son>
        </div>
    </body>

But this is not a correct way of doing things, this has many problems as you can imagine.

Directive Scope Binding

Above we saw a very simple, but incorrect way of doing scope binding with a directive. Angular provides us with different ways to do this, lets see the correct way to do this

            var app = angular.module('app', []);
            app.controller('ctrl', function ($scope) {
                $scope.name = 'Manish';
                $scope.about = {
                    age: 28,
                    lastname: 'Prakash'
                }
                $scope.name2 = 'Prakash';
                $scope.about2 = {
                    age: 30,
                    lastname: 'G'
                }
            });
            app.directive('mySon', function () {
                return {
                    restrict: 'E',
                    scope: {
                        firstname: '=firstname',
                        my: '=about'

                    },
                    template: '<div>My Name is {{firstname}}</div><div>Age {{my.age}} Lastname {{my.lastname}}</div>'
                };
            });
    <body ng-app="app">
        <div ng-controller="ctrl">
            <my-son firstname='name' about='about'></my-son>
            <my-son firstname='name2' about='about2'></my-son>
        </div>
    </body>

Above we use a different way of passing scope through directive attributes. In this we are able to use a single controller and make the directive reusable.
There are many different ways to use the “scope” property in a directive, which can be seen here
https://docs.angularjs.org/api/ng/service/$compile#-scope-

Lets look at all the different methods and their implications.

Isolate Scope

The above method which we saw of passing scope variables through attribute is called isolate scope. This basically creates new scope, which doesn’t inherent from the parent controller scope.
Isolate Scope using =
As per angular documentation

= or =attr - set up bi-directional binding between a local scope property and the parent scope property of name defined via the value of the attr attribute. If no attr name is specified then the attribute name is assumed to be the same as the local name. 

So what this does is setup bi directional binding of scope with directive. Lets look at an example for this

In the above we see due to bi-direction we can update the scope from both controller and directive.

Isolate Scope using @
As per angular documentation

@ or @attr - bind a local scope property to the value of DOM attribute. The result is always a string since DOM attributes are strings. If no attr name is specified then the attribute name is assumed to be the same as the local name

So this doesn’t setup any kind of data binding, rather takes the value directly as a test value. Lets take a example of previous case only and see what happens.

As you can see in above code, in the first version it shows name as “name”, it doesn’t interpolate it.
It works in the second version using {{name}} but we are not able to pass an object through this method.
This type is mainly useful for passing strings with one time data binding.

Isolate Scope = &
This type of scope is a little more complex than other two which we have seen. As per documentation

& or &attr - provides a way to execute an expression in the context of the parent scope. If no attr name is specified then the attribute name is assumed to be the same as the local name. Often it's desirable to pass data from the isolated scope via an expression to the parent scope, this can be done by passing a map of local variable names and values into the expression wrapper fn. For example, if the expression is increment(amount) then we can specify the amount value by calling the localFn as localFn({amount: 22}).

This is mainly used when we need to call a controller function directly from directive.
Lets see an example using code

In the above code, if you write something in the text field, and press click here you will see the value alert box.
We are calling the function of a controller and passing scope paramter to it through isolate scope.

Scope = true
This method doesn’t create a isolate scope. Rather this is used to create a new scope altogether with no properties.

If set to true, then a new scope will be created for this directive. If multiple directives on the same element request a new scope, only one new scope is created

Here are some more references to interesting articles which you should go through

http://stackoverflow.com/questions/16502559/using-a-directive-inside-an-ng-repeat-and-a-mysterious-power-of-scope
http://stackoverflow.com/questions/11913841/accessing-attributes-from-an-angularjs-directive
http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html
http://juristr.com/blog/2014/11/learning-ng-what-is-your-directives-scope/