ng-model does not update properly

advertisements

I have a structure like this (much simplified):

<div ng-controller="MainCtrl">
  <div>Views and other stuff</div>
    <div ng-controller="MyCtrl">
      <div ng-repeat="item in $root.items track by $index">
        {{item.id}}
      </div>
    <div>
        Total value: {{totVal}}
    </div>
  </div>
</div>

And in my main controller I have defined $rootScope.items = [{id: 1,..},{id: 2,..},{id: 3,..},..] and in my other controller I have defined $scope.totVal = 0 and a watcher for the items array which updated the totVal when the items array changes;

.controller('MainCtrl', ['$rootScope', '$scope', function($rootScope, $scope) {
    // Are actually fetched from a service
    $rootScope.items = [
        {id: 1,..},
        {id: 2,..},
        ..
    ];
}])

.controller('MyCtrl', ['$rootScope', '$scope', function($rootScope, $scope) {
    $rootScope.updateTotVal = function() {
        var totVal = 0;
        // calculations are done here
        // Is correct here when I console log after all calculations are complete
        console.log(totVal);
        $scope.totVal = totVal;
    }

    $scope.totVal = 0;

    $rootScope.$watch('items', function() {
        $rootScope.updateTotVal();
    }, true);
}]);

The problem I have is that the totVal does not update in the view. When I console log the value it displays correctly in the console but it only updates in the view if I scroll the totVal div out of view and back again. Seems like an AngularJS bug in Chrome, but can't find any similar cases when i Google. It works fine in FireFox.

If I move the totVal before the ng-repeat it works and if I remove the ng-repeat it works (I rather don't change the structure of the html since it will be much work and make the design worse). I have also tried to move the totVal to the root scope without any success.

It's only the painting/rendering that fails, Batarang and console.log always gives me the updated value.

Has anyone had this problem before?


I don't know if this is exactly what you where looking for because I don't know your use case. However, I achieved a working example, see it here codepen.

I refactored your code a bit, removing the extra controller and encapsulated totVal in a service. Also, I use the controllerAs syntax to make everything clearer.

The problem with your code is the fact that totVal is a primitive. Thus, when you assign it a new value, angular will not be able to update the reference. This is why you should always have a dot in your model!

Take a look at my code, you will se that I declared totVal as var totVal = {val : 0}. I simply update val, the reference is kept and the view is correctly updated.

.service('totVal', function(){
  var totVal = {val:0};

  this.computeTotVal = function(){
    //perform computations, I will just increment
    totVal.val++;
  }

  this.getTotVal = function() { return totVal; }
})

See also this article.