0

The jsFiddle for this question can be found here: http://jsfiddle.net/Hsw9F/1/

JavaScript (console.log debug information available in the jsFiddle)

var app = angular.module('StackOverflow',[]);

function ParentController($scope) {
 $scope.parentCounter = 5;
}

function ChildController($scope) {
  $scope.childCounter = $scope.parentCounter;
  $scope.increaseCounters = function() {
    ++$scope.parentCounter;
    ++$scope.childCounter;
  };
}

In the example above I have a counter in the parent and the child controllers named parentCounter and childCounter respectively. I've also provided a function in the child controller named increaseCounters() that increases both counters by one.

Both of these counters are displayed on the page:

<div ng-app="StackOverflow">
  <div ng-controller="ParentController">

    Parent Counter: {{parentCounter}}<br />

    <div ng-controller="ChildController">
      Child Counter: {{childCounter}}<br />
      <a href="javascript:void(0)"
         ng-click="increaseCounters()">Increase Counters</a>
    </div><!-- END ChildController -->

  </div><!-- END ParentController -->
</div><!-- END StackOverflow app -->

The problem is that AngularJS doesn't seem to update the {{parentCounter}} on the page, and only updates the {{childCounter}} when the increase counters function is called. Is there anything I have overlooked?

Jay
  • 18,959
  • 11
  • 53
  • 72

2 Answers2

3

++$scope.parentCounter; creates a child scope property with name parentCounter that hides/shadows the parent scope property of the same name.

Add console.log($scope); to your increaseCounters() function to see it.

One workaround: ++$scope.$parent.parentCounter;

The problem you are experiencing has to do with the way JavaScript prototypal inheritance works. I suggest reading What are the nuances of scope prototypal / prototypical inheritance in AngularJS? -- it has some nice pictures explaining what happens when primitives are created in child scopes.

Community
  • 1
  • 1
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • You're right - in this case using `$scope.$parent.parentCounter` makes it function properly - http://jsfiddle.net/Hsw9F/4/. – Jay Jan 09 '13 at 21:07
  • 1
    @Trevor, I added a link to my answer that should be helpful. – Mark Rajcok Jan 09 '13 at 21:10
  • One drawback of using $scope.$parent.parentCounter is when you move the parent or place another controller in between, that it will break. – asgoth Jan 09 '13 at 21:22
  • @asgoth, thanks, I was being lazy. I should have mentioned all 3 alternatives (I added a comment to your answer about the 3rd way). – Mark Rajcok Jan 09 '13 at 23:19
2

Because the child controller gets a copy of the parent counter value. If you want to increase the parent controller counter value, you need to execute a function on the parent controller:

function ParentController($scope) {
 $scope.parentCounter = 5;

  $scope.increaseParent = function() {
     ++$scope.parentCounter;
  };
}

function ChildController($scope) {
  $scope.childCounter = $scope.parentCounter;
  $scope.increaseCounters = function() {
    console.log('-------------------------------------');
    console.log('parent before: ' + $scope.parentCounter);
    console.log('child before: ' + $scope.childCounter);
    $scope.increaseParent();
    ++$scope.childCounter;
    console.log('parent after: ' + $scope.parentCounter);
    console.log('child after: ' + $scope.childCounter);
  };
}
asgoth
  • 35,552
  • 12
  • 89
  • 98
  • For completeness, there's one more alternative: use an object in the parent scope. E.g., `$scope.someObj = { parentCounter: 5 }` then in increaseCounters(), `++$scope.someObj.parentCounter`. Due to prototypal inheritance, when the child scope looks for $scope.someObj, it will find it in the parent, then modify the parentCounter property. (This is also explained in the link I provided.) – Mark Rajcok Jan 09 '13 at 23:18