Question

In case below changing of any input will cause changing in all of them. As I understood, it happens because data object is common for all of 3 scopes

<div class="content-container" ng-app="">
<input type="text" ng-model="data.message">
<h1>{{data.message}}</h1>
<div ng-controller="FirstController">
    <input type="text" ng-model="data.message">
    <h1>{{data.message}}</h1>
</div>
<div ng-controller="SecondController">
    <input type="text" ng-model="data.message">
    <h1>{{data.message}}</h1>
</div>

but in case below each scope will have it's own message object:

<div class="content-container" ng-app="">
<input type="text" ng-model="message">
<h1>{{message}}</h1>
<div ng-controller="FirstController">
    <input type="text" ng-model="message">
    <h1>{{message}}</h1>
</div>
<div ng-controller="SecondController">
    <input type="text" ng-model="message">
    <h1>{{message}}</h1>
</div>

It is not clear for me, why angular create "message" object for each scope but do not create "data" object for each scope? What is the major difference between this two examples?

Was it helpful?

Solution

It's not about how AngularJS works - it's about how JavaScript works, actually. Consider the following:

function Parent() { 
  this.message = ''; 
  this.data    = {};
}
function Child() {}; Child.prototype = new Parent();

As you see, Parent, when used as a constructor, defines two properties for a fresh object. Let's say we're going to use the first one to store a primitive, and the second one to store an object.

Child function is defined really simple: no properties of its own, having Parent object in its prototype chain. Now that's do some more things with them:

var c = new Child();
c.message      = '42';
c.data.message = '42';
console.log(c.hasOwnProperty('message'));         // true
console.log(c.hasOwnProperty('data'));            // false
console.log(c.data.hasOwnProperty('message'));    // true

See the difference? In the first case, with c.message, we have defined a new property on a child object (c) itself - and that one now shadows the same-named property defined on its prototype.

In the second case, however, we are still using the property of parent, extending its value with a new property. No new properties are defined on c, only its prototype is affected; the difference is even more telling here:

var d = new Child();
d.message      = '34';
d.data.message = '34';

console.log(c.message);      // still '42'
console.log(c.data.message); // now '34'

Similar things happen when you use Angular directive: a new scope is defined, inheriting all the 'model' properties from its parent scope. But unless these properties are 'two-level', assigning to them will introduce the same-named property on a child level, shadowing the one defined for the parent.

I'd suggest studying Understanding Scopes document from Angular wiki: it has much more substantial (and richly illustrated, too!) explanation for this behavior. This quote, however, summarizes it pretty well:

This issue with primitives can be easily avoided by following the "best practice" of always have a '.' in your ng-models.

And it has some workarounds mentioned for the cases when one indeed wants to work with primitives only: $parent.parentScopeProperty is the most straight-forward one, I suppose.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top