Reputation: 799
I have read in different places that it is important that you always use objects in your scope but I haven't found a definitive answer as to why that is. Can someone please help me?
Upvotes: 2
Views: 465
Reputation: 2301
Because then you keep the data in one place. A child scope (which is not an isolated scope) can shadow a property "message" for example. So the parent scope and the child scope have a "message" property. But if the parent scope has "data.message" property, the child scope cannot shadow this, unless first a property "data" is created in the child scope, and then "data.message", but this is not what AngularJS does. But AngularJS indeed creates first "data" and then "data.message" in the parent scope.
Upvotes: 0
Reputation: 799
I like Ryan Q's answer but after doing some more research I wanted to add an answer with a little more emphasis on javascript's prototypal inheritance.
The issue here is an object vs. primitive issue (pass by reference and pass by value) and how Javascript’s prototypal inheritance works.
When a javascript class inherits from a parent class, it copies the values over into the child class. There are two types of values that could be copied over, objects or primitives.
When an object is copied in through inheritance, it is passed by reference. This means that any updates I make in my child object will be seen in the parent object as well.
When a primitive is copied in through inheritance, it is passed by value. This means that any updates will NOT be seen in the parent class.
What does this have to do with Angular scopes? When we create a directive, a scope will be created for this directive and we can declare it to be an isolated scope or an inherited scope. If it is an inherited scope, it will inherit its parent’s scope items. Now, if I have primitive values in my parent scope, I will be inheriting them into my child scope as pass by value. Which means when I make a change in my parent scope, it won’t be seen in my child scope, and vice versa. Now I could have the same inherited variable in my child and parent scope with different values. This is going to lead to confusion…. And probably anger…lol.
So if you just use an object, then this problem will not happen. And that is why you should always objects in scopes.
Upvotes: 5
Reputation: 10683
Lets say you have 3 controllers, a main control, and two others which inherit from the main control.
Your html might look like this.
<div ng-controller="MainCtrl">
<div ng-show="helloWorld">Hello World</div>
<div ng-controller="Sub1Ctrl">
<button type="button" ng-click="helloWorld = false">Hide Hello World</button>
</div>
<div ng-controller="Sub2Ctrl">
<button type="button" ng-click="helloWorld = false">Hide Hello World</button>
</div>
</div>
Your Main Controller
angular.module('MyModule').controller('MainCtrl', function( $scope ){
$scope.helloWorld = true;
});
All is fine and dandy and your hello world element shows as expected. Now try clicking one of those buttons which sets helloWorld to false. Your Sub1Ctrl will now look like this:
angular.module('MyModule').controller('Sub1Ctrl', function( $scope ){
$scope.helloWorld = false;
});
But your MainCtrl will still be
angular.module('MyModule').controller('MainCtrl', function( $scope ){
$scope.helloWorld = true;
});
Why is that? Well because when Angular evaluates "helloWorld = false" it sets $scope["helloWorld"] = false internally. The issue is because your setting it on the lower Sub1Ctrl, the higher controller is never set.
If you change your Html and MainCtrl to this:
<div ng-controller="MainCtrl">
<div ng-show="myModel.helloWorld">Hello World</div>
<div ng-controller="Sub1Ctrl">
<button type="button" ng-click="myModel.helloWorld = false">Hide Hello World</button>
</div>
<div ng-controller="Sub2Ctrl">
<button type="button" ng-click="myModel.helloWorld = false">Hide Hello World</button>
</div>
</div>
angular.module('MyModule').controller('MainCtrl', function( $scope ){
$scope.myModel = {
helloWorld: true
}
});
Then Angular will look up and see if the object exists in the scope's prototype (which is how controllers inherit through the Scope Hierarchy) before setting the value.
So now Angular evaluates "myModel.helloWorld" on the Sub1Ctrl which ends up finding "myModel" on the parent MainCtrl and so properly sets the helloWorld property to false.
Upvotes: 1
Reputation: 2654
Take a look at this: https://github.com/angular/angular.js/wiki/Understanding-Scopes and Does my ng-model really need to have a dot to avoid child $scope problems?
Upvotes: 1