Blitz
Blitz

Reputation: 259

Why is ng-model not updating?

I am trying to do a simple angularJS test with a input[type=checkbox] and show the number of items that are selected. Currently, my solution looks like this:

Controller:

$scope.items = [{
    id: 1,
    title: 'item1',
    selected: true
},{
    id: 2,
    title: 'item2',
    selected: false
},{
    id: 3,
    title: 'item3',
    selected: false
},{
    id: 4,
    title: 'item4',
    selected: false
}]

$scope.$watchCollection('items', function() {
    var no = 0;
    for(var i = 0; i < $scope.items.length; i++) {
        if($scope.items[i].selected === true)
            no++;
    }
    $scope.noSelectedItems = no;
}

View:

<div>Items ({{ noSelectedItems }})</div>
    <div ng-repeat="item in items">
        <input id="{{ item.id }}"
               type="checkbox"
               ng-model="item.selected"
               ng-checked="item.selected" />
    <label for="{{ item.id }}" >{{ item.title }}</label>
</div>

The initialization works, so I get "Items (1)" but when I select more items, the $scope.items doesn't update at all.

Can anyone explain why?

Thank you.

Upvotes: 1

Views: 53

Answers (2)

You need to do a deep watch in your collection, using the third parameter (true) in $watch. See the working JSFiddle: http://jsfiddle.net/syv8cww1/

$scope.$watch('items', function() {
    var no = 0;
    for(var i = 0; i < $scope.items.length; i++) {
        if($scope.items[i].selected === true)
            no++;
    }
    $scope.noSelectedItems = no;
}, true);

Upvotes: 2

meriadec
meriadec

Reputation: 2983

$watchCollection is not designed to watch updates inside objects in an array of objects. See offical docs for more infos.

You can resolve your problem by using ngChange directive.

HTML :

<div ng-repeat="item in items">
    <input id="{{ item.id }}"
           type="checkbox"
           ng-model="item.selected"
           ng-checked="item.selected"
           ng-change="doSomething()"/>
</div>

Controller :

$scope.doSomething = function() {
  var no = 0;
  for(var i = 0; i < $scope.items.length; i++) {
    if($scope.items[i].selected === true) {
      no++;
    }
  }
  $scope.noSelectedItems = no;
}

Upvotes: 0

Related Questions