2

I'm following a book, and using this version of Angular: https://ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js[1]

This is my template:

<div ng-controller="ParentController">
    <div ng-controller="ChildController">
        <a ng-click="sayHello()">Say hello</a>
    </div>
    {{ person }}
</div>

This is my controller code:

app.controller('ParentController', function ($scope) {
    $scope.person = { greeted: false };

});

app.controller('ChildController', function ($scope) {
    $scope.sayHello = function () {
        $scope.person = { name: "Ari Lerner", greeted: true };
    }
});

I noticed my code doesn't doesn't update the template as expected unless I change my sayHello method to this:

$scope.sayHello = function () {
    $scope.person.name = "Ari Lerner";
    $scope.person.greeted = true;
};

Any insight as to why this might be? I was under the assumption that updating person would be reflected in the DOM.


Using 1.4.2 yields the same result.

Thinking that maybe the properties are somehow indexed differently, I tried the following:

$scope.person.name = { greeted: true, name: "Ari Lerner" };

(switched greeted and name)

Wild speculation: It seems to me that something in Angular is holding on to the original object that was assigned to $scope.person and setting $scope.person to a new object "loses" the data binding. Is this true?

beefsupreme
  • 125
  • 1
  • 1
  • 9
  • Because you are creating a child scope and thus need the dot notation. – ajmajmajma Jul 08 '15 at 15:39
  • 2
    To edit $scope.person from the childController (child scope) use $scope.$parent like so... $scope.$parent.person = { name: "Ari Lerner", greeted: true }; – timsmiths Jul 08 '15 at 15:41
  • @timsmiths That's not a good practice to use. – Agop Jul 08 '15 at 15:54
  • Thanks @Agop, appreciate the feedback! – timsmiths Jul 08 '15 at 15:56
  • @Agop: Is this just a poor example in the book for production-level code? Would the sayHello method be better suited for parentController? – beefsupreme Jul 08 '15 at 17:30
  • 1
    @beefsupreme It's hard to say without knowing the context of this example in the book. For example, was it trying to show the pitfalls of prototypical inheritance? If yes, then it did a great job. Otherwise, you may be right, it may just be a bad example, considering it doesn't even work! :) – Agop Jul 08 '15 at 17:42
  • It was an example showing what prototypical inheritance is. The book specifically assigns the values to $scope.person.name and $scope.person.greeted. I thought it might be the same as assigning to $scope.person, but apparently that's wrong. I'm new to prototypical inheritance. Sounds like I should just avoid it for now since I'm pretty newbie. – beefsupreme Jul 08 '15 at 17:59
  • @beefsupreme Ah, I see. Then it sounds like the book just didn't explain it well enough. It may be hard to avoid prototypical inheritance in AngularJS, so take another read over my answer, and definitely visit my link to that other question and answer. It'll be a big help. – Agop Jul 08 '15 at 18:19

4 Answers4

2

In AngularJS, scopes use prototypical inheritance from their parents.

Prototypical inheritance basically means that JavaScript will look at the parent scope if it doesn't find a property on the child scope.

So, when you do $scope.person.name = 'Ari Lerner', JavaScript looks at $scope, sees that it doesn't have a person property, then goes to its parent (the parent scope), sees that it has a person property, and assigns the name property of that to 'Ari'.

On the other hand, when you do $scope.person = { ... }, JavaScript doesn't care if the property exists or not - it simply carries out the assignment, ensuring that your $scope now has a person property. The problem here is that your child scope's person property now shadows the person property of the parent scope, which still has its original value. So, in the parent controller, person never changed.

For further reading, check this answer here:

What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

Community
  • 1
  • 1
Agop
  • 1,907
  • 17
  • 23
0

You are creating a child scope that prototypically inherits from its parent scope. This is the case unless you are using an isolate scope (directive).

For a really great explanation, see here What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

Community
  • 1
  • 1
ajmajmajma
  • 13,712
  • 24
  • 79
  • 133
0

As others stated, this is because of your scopes.

For example, if you want to create a new object in your childScope, you do $scope.someObject = {};. Now, JavaScript can't know the difference between

$scope.someNewObject = {};

and

$scope.person = {};

because you are just assigning a new object to your childscope. The other notation works, because by grabbing $scope.person.attribute = ... JavaScript knows, that the person object already exists. It starts looking for this object in your childscope, can't find it there, goes to parentscope and finds it there and sets the attribute.

In conclusion you either have to use $scope.person.attribute, or you use $scope.$parent.person = {};

Andreas Grünh
  • 336
  • 1
  • 6
-2

To edit $scope.person from the childController (child scope) use $scope.$parent like so...

app.controller('ChildController', function ($scope) {
    $scope.sayHello = function () {
        $scope.$parent.person = { name: "Ari Lerner", greeted: true };
    }
});
timsmiths
  • 167
  • 6