AngularJs Directive Isolated Scopes

What is Isolate Scope?

Directives have access to the parent scope by default in AngularJS applications. For example, the following directive relies on the parent scope to write out a customer object’s name and street properties:

angular.module('MyModule').directive('MyDirective', function () {
    return {
        template: 'Name: [[ user.name ]] Street: [[ user.street ]]' // print symbols are Interpolated

    };
});

Although this code gets the job done, you have to know a lot about the parent scope in order to use the directive and could just as easily use ng-include and an HTML template to accomplish the same thing (this was discussed in the first post). If the parent scope changes at all the directive is no longer useful. If you want to make a reuseable directive you can’t rely on the parent scope and must use something called Isolate Scope instead. Here’s a diagram that compares shared scope with isolate scope:

Creating Isolated

Isolating the scope in a directive is a is a simple process. Start by adding a scope property into the directive as shown next. This automatically isolates the directive’s scope from any parent scope(s).

angular.module('MyModule').directive('MyDirective', function () {
    return {
        scope: {},
        template: 'Name: [[ user.name ]] Street: [[ user.street ]]' // print symbols are Interpolated

    };
});

@ Scope Property

The @ local scope property is used to access string values that are defined outside the directive. For example, a controller may defined a name property on the $scope object and you need to get access to that property within the directive. To do that, you can use @ within the directive’s scope property. Here’s a high level example of that concept with a step-by-step explanation:

  • A controller defines $scope.name.
  • The $scope.name property value needs to be passed into the directive.
  • The directive creates a custom local scope property within its isolate scope named name (note that the property can be named anything and doesn’t have to match with the $scope object’s property name). This is done using scope { name: ‘@’ }.
  • The @ character tells the directive that the value passed into the new name property will be accessed as a string. If the outside value changes the name property in the directive’s isolate scope will automatically be updated.
  • The template within the directive can now bind to the isolate scope’s name property.

angular.module('MyModule').controller('UsersController', ['$scope', function ($scope) {
    var counter = 0;
    $scope.users = {
        name: 'John',
        street: 'xxxx Anywhere St.'
    };
            
    $scope.users = [
        {
            name: 'John',
            street: 'xxxx Anywhere St.'
        },
        {
            name: 'Mike',
            street: 'xxxx Crest St.'
        },
        {
            name: 'Tom',
            street: 'xxxx Main St.'
        }
    ];
}]);

///////////////////////////////////////////////////////////////////

angular.module('MyModule').directive('MyDirective', function () {
    return {
        scope: {
          name: '@name',
          street: '@street'
        },
        template: 'Name: [[ name ]] Street: [[ street ]]'
    };
});
<div my-directive name="[[ user.name ]]" street="[[ user.street ]]"></div>
<!--We've just used Angular Interpolation to change print symbols-->

= Scope Property

The @ character works well for accessing a string value that is passed into a directive as shown in the previous example. However, it won’t keep changes made in the directive in-sync with the external/outer scope. In cases where you need to create a two-way binding between the outer scope and the directive’s isolate scope you can use the = character. Here’s a high level example of that concept with a step-by-step explanation:

  • A controller defines a $scope.person object.
  • The $scope.person object needs to be passed into the directive in a way that creates a two-way binding.
  • The directive creates a custom local scope property within its isolate scope named customer. This is done using scope { customer: ‘=’ }.
  • The = character tells the directive that the object passed into the customer property should be bound using a two-way binding. If the outside property value changes then the directive’s customer property should automatically be updated. If the directive’s customer property changes then the object in the external scope should automatically be updated.
  • The template within the directive can now bind to the isolate scope’s customer property.