Scope in AngularJS

30 / Jun / 2014 by Amit Kumar 2 comments

When we work on AngularJS, scope become very important concept. So today we will understand the Scope in AngularJS. In almost every AngularJS Controller we use scope object which is auto injected by AngularJS in $scope named parameter. And that scope gets visible to marked HTML and its inner/child HTML, because of which HTML can access all the properties and methods which are defined into the scope object. And if anything gets changed in the scope, it will automatically reflect into the HTML and if anything gets changed in HTML it will automatically reflect into scope object via $watch method. In-fact AngularJS provides two-way-data-binding with the help of $scope and $watch method. After reading this we might think scope is a very simple concept in AngularJS. But sorry that is not true :-( . When we write directives, it gets confusing and complicated to understand. But don’t worry, I promise, today after reading this blog you will get to understand scope with directives and you will feel pretty confident with scope :-) .

Note: I will discuss scope concept with AngularJS 1.2 version, in older version scope concept was a bit different.

In a directive, we can use any one among these three values for scope parameter/field:

1. false – Parent Scope
2. true – Inherited Scope
3. Object hash/{} – Isolated Scope

Lets first make a basic application with small HTML and a Controller(ScopeTestController) then we will understand scope with examples:

HTML:

<body ng-controller="ScopeTestController">
<div>
    ScopeTestController: {{scopeName}} {{controllerField}}
    <!-- ScopeTestController: ScopeTestController controllerField -->
</div>
<hr/>
</body>

Controller:

/*
 * Defining ScopeTestController with two scope fields
 * */
var scopeTestApp = angular.module('scopeTest', []);

function ScopeTestController($scope) {
    $scope.scopeName = "ScopeTestController";
    $scope.controllerField = "controllerField";
}

1. Scope = false: You might be thinking that directive creates inherited scope by default same as controller but that is not true. Default value of scope for all directives is false and those directives get same scope as of their parent. So whatever changes we make in this scope, will reflect in parent’s scope and changes done in parent scope will reflect to this scope as both are exact same scope object.

Defining a parent scope directive with parentScopeTestWithTemplate name:

scopeTestApp.directive('parentScopeTestWithTemplate', function () {
    return {
        // Default value of scope is false. 'scope false' uses the same scope in which it is defined means Parent Scope.

        link: function (scope) {
            scope.scopeName = "parentScopeTestWithoutTemplate";
        },
        template: 'parentScopeTestWithTemplate: {{scopeName}} {{controllerField}}'
    };
});

Using parentScopeTestWithTemplate directive in HTML:

<body ng-controller="ScopeTestController">
<div>
    ScopeTestController: {{scopeName}} {{controllerField}} <!-- ScopeTestController: parentScopeTestWithoutTemplate controllerField -->
</div>
<!-- This uses Parent Scope, i.e the default one. So same scope will be on directive, template/templateUrl and on HTML. -->

<div parent-scope-test-without-template>
    sameScopeTestWithoutTemplate: {{scopeName}} {{controllerField}} <!-- ScopeTestController: parentScopeTestWithoutTemplate controllerField -->
</div>
<hr/>
</body>

You will see HTML print parentScopeTestWithTemplate for scopeName in both the places(inside the directive as well outside the directive) that is because of parent scope directive only, parent scope directive uses same parent scope and it updates the value of scopeName field so it is reflected in both the places. ngShow and ngHide are examples of Parent Scope Directive.

Note: If we are manipulating the scope then we should not make use of Parent Scope(false for scope parameter/field) directive because it is a bad practice that we are modifying same scope object at more than one places.

2. Scope = true: this creates a new inherited scope from parent scope. And this scope gets visible in inner/child HTML, in directive and in template(if we have defined). If we override any field of parent scope in newly created inherited scope then that updated value will be applied only in inner/child HTML and template.

Defining an inherited scope directive with inheritedScopeTestWithTemplate name:

scopeTestApp.directive('inheritedScopeTestWithTemplate', function () {
    return {
        // 'scope true' creates a new inherited Scope.

        scope: true,
        link: function (scope) {
            scope.scopeName = "inheritedScopeTestWithTemplate";
        },
        template: 'inheritedScopeTestWithTemplate: {{scopeName}} {{controllerField}}'
    };
});

Using inheritedScopeTestWithTemplate directive in HTML:

<body ng-controller="ScopeTestController">
<div>
    ScopeTestController: {{scopeName}} {{controllerField}} <!-- ScopeTestController: ScopeTestController controllerField -->
</div>
<!-- inherited Scope is visible in template/templateUrl, directive and inner HTML -->

<div inherited-scope-test-without-template>
    inheritedScopeTestWithoutTemplate: {{scopeName}} {{controllerField}} <!-- ScopeTestController: inheritedScopeTestWithoutTemplate controllerField -->
</div>
<hr/>
</body>

3. Scope = {}: This creates new isolated scope. And this scope is visible in directive and in template(if we have defined) only. Parent scope will not get visible in directive and template. Before Angular1.2 version, isolated scope was visible in inner/child HTML, but now after Angular1.2 version, isolated is, as its name says, actually completely isolated.

<strong>Defining an isolated scope directive with isolatedScopeTestWithTemplate name:</strong>
scopeTestApp.directive('isolatedScopeTestWithTemplate', function () {
    return {
        // 'scope object hash' creates a new isolated Scope.

        scope: {},
        link: function (scope) {
            scope.scopeName = "isolatedScopeTestWithTemplate";
        },
        template: 'isolatedScopeTestWithTemplate: {{scopeName}} {{controllerField}}'
    };
});

Using isolatedScopeTestWithTemplate directive in HTML:

<!-- Isolated Scope get only visible in template/templateUrl and directive only but is not visible in inner HTML -->

<div isolated-scope-test-with-template>
    isolatedScopeTestWithoutTemplate: {{scopeName}} {{controllerField}} <!-- ScopeTestController: isolatedScopeTestWithoutTemplate -->
</div>

You will see directive template HTML printed only the value of scopeName but does not print the value of controllerField, because Parent scope does not get visible in template and isolated scope has only scopeName property.

NOTE: If we do not provide template in isolated scope directive then inner/child HTML will get parent scope instead of isolated scope, because isolated scope only gets visible in template HTML and in directive. So only parent scope properties and methods will be accessible in inner/child HTML.
Parent Scope will not be visible into isolated scope, but many a times we face a requirement when we need to access parent scope properties/methods into isolated scope then we can use notations symbols, which we will discuss in next blog. But we do not face this issue with parent scope and inherited scope because parent scope is the exactly same scope and inherited scope gets visible in inner/child HTML.

MISCELLANEOUS:

1. Two or more directive with template/templateUrl on same node gives error, so if try below code it gives error.

<!--<div isolated-scope-test-with-template inherited-scope-test-with-template>
    isolatedInheritedParentScopeTestWithoutTemplate: {{scopeName}} {{controllerField}}
</div>
<hr/>-->

2. Suppose If we are marking two directives(A and B) on same HTML node/element, and template is defined into directive A, then template will get scope of directive A(its own directive) only. And if one directive has inherited scope(suppose A is an inherited scope directive) and one directive has isolated scope(suppose B is an isolated scope directive) then inherited scope will be applied to inner HTML(because after AngularJS 1.2 isolate scope will be visible in directive and its own template only). And if two inherited scope or isolated scope directive are marked on same node(means either both A and B are isolated scope directive or inherited scope directive) then both will get the exactly same inherited or isolated scope respectively.

<strong>isolated</strong> <strong>scope</strong> respectively.
<div isolated-scope-test-with-template inherited-scope-test-without-template>
</div>
<hr/>
<div isolated-scope-test-without-template inherited-scope-test-with-template>
</div>
<hr/>
<div isolated-scope-test-without-template inherited-scope-test-without-template>
    ScopeTestController: {{scopeName}} {{controllerField}}
</div>
<hr/>
<div inherited-scope-test-without-template inherited-scope-test2-without-template>
    ScopeTestController: {{scopeName}} {{controllerField}}
</div>
<hr/>

Note: You can checkout full working source code from this link.

Amit Kumar
amit.kumar@intelligrape.com
in.linkedin.com/in/amitkumar0110
twitter.com/amit_kumar0110
More Blogs by Me

FOUND THIS USEFUL? SHARE IT

comments (2)

Leave a comment -