1

I am absolutly new in AngularJS and I am study it on a course. I have some doubt on an example that show how to use the isolation scope concept.

So the provided example is a single page application that contain this app.js file that contain all the application logic:

var myApp = angular.module('myApp', ['ngRoute']);

myApp.config(function ($routeProvider) {

    $routeProvider

    .when('/', {
        templateUrl: 'pages/main.html',
        controller: 'mainController'
    })

    .when('/second', {
        templateUrl: 'pages/second.html',
        controller: 'secondController'
    })

    .when('/second/:num', {
        templateUrl: 'pages/second.html',
        controller: 'secondController'
    })

});

myApp.controller('mainController', ['$scope', '$log', function($scope, $log) {

    $scope.person = {
        name: 'John Doe',
        address: '555 Main St., New York, NY 11111'
    }

}]);

myApp.controller('secondController', ['$scope', '$log', '$routeParams', function($scope, $log, $routeParams) {



}]);


/* Declare a directive named "searchResult" */
myApp.directive("searchResult", function() {
   return {
       restrict: 'AECM',                                // This represent the ways to declare the directive into my code
       templateUrl: 'directives/searchresult.html',     // This is the template page that implement the directive
       replace: true,                                   // This specify that the directive in the main HTML code is replaced by the template code

       /* This isolate the directive scope (the model of the directive) from its parent scope (the controller that handle the page in which
        the directive is used). Because I can't directly use the person.name and the person.address property declared in the parent scope I
        specify that I use the person-name and the person-address passed as custom attribute of the search-result directive where it is used (in         the main.html)
       */
       scope: {
           personName: "@",
           personAddress: "@"
       }
   }
});

This is the main.html page that is where the search-result directive is used:

Search

<h3>Search Results</h3>
<div class="list-group">
    <search-result person-name="{{ person.name }}" person-address="{{ person.address }}"></search-result>
</div>

And this is the code of the searchResult.html that is the template of my directive:

<a href="#" class="list-group-item">
    <h4 class="list-group-item-heading">{{ personName }}</h4>
    <p class="list-group-item-text">
        {{ personAddress }}
    </p>
</a>

So, from what I have understand (but correct me if I am doing wrong assertion) the scope isolation works in the following way:

To avoid problem I can isolate the scope of a child directive by its parent scope (for example the controller of the main page).

To do it I have simply to insert a scope JSON object into the directive JavaScript declartation:

scope: {
    .............
    .............
    .............
}

But now from my directive I can't directly access no more to the name and address properties declared in the parent scope (the controller scope).

So if I have to use these value I declare the isolated directive scope object in this way:

scope: {
    personName: "@",
    personAddress: "@"
}

that means that the personName property have the textual value of the person-name declared in the search-result HTML declaration (and the dame thing for the personAddress, infact in my main.hml file I have

<search-result person-name="{{ person.name }}" person-address="{{ person.address }}"></search-result>

and from here I can directly access to the person.name and to the person.address because here I am using the controller scope (the parent scope)

So now in my JavaScript directive I obtained these values into the personName and personAddress property of the isolated child scope object and in my directive template I access to these properties, in this way:

<a href="#" class="list-group-item">
    <h4 class="list-group-item-heading">{{ personName }}</h4>
    <p class="list-group-item-text">
        {{ personAddress }}
    </p>
</a>

Is it my reasoning correct or am I missing something?

AndreaNobili
  • 40,955
  • 107
  • 324
  • 596

4 Answers4

1

This is correct. Using an isolated scope on your directive makes it usable in new contexts without the danger of polluting its parent scope.

1

@ Attribute string binding = Two-way model binding & Callback method binding

deeper understanding scope of directive

enter link description here

Community
  • 1
  • 1
finnishare
  • 11
  • 2
1

Your understanding is correct. Isolate scope differs from normal scope in that it does not prototypically inherit from its parent scope. This is useful when creating reusable components, which should not accidentally read or modify data in the parent scope, and it is also not strongly coupled with parent scope.

To expand on what is available through isolated scope, there are three options available to you (from the 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. Given and widget definition of scope: { localName:'@myAttr' }, then widget scope property localName will reflect the interpolated value of hello {{name}}. As the name attribute changes so will the localName property on the widget scope. The name is read from the parent scope (not component scope).

= 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. Given and widget definition of scope: { localModel:'=myAttr' }, then widget scope property localModel will reflect the value of parentModel on the parent scope. Any changes to parentModel will be reflected in localModel and any changes in localModel will reflect in parentModel. If the parent scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You can avoid this behavior using =? or =?attr in order to flag the property as optional. If you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use =* or =attr (=? or =*?attr if the property is optional).

& 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. Given and widget definition of scope: { localFn:'&myAttr' }, then isolate scope property localFn will point to a function wrapper for the count = count + value expression. 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}).

Beyers
  • 8,968
  • 43
  • 56
1

i have explained the how scope isolation work and in corresponding to rootScope in answer to another question

$scope and $rootscope confusion

Please let me know if this help

Community
  • 1
  • 1
Avinash Jain
  • 7,200
  • 2
  • 26
  • 40