0

I have some issues getting notifications from changes in a list if I use an input field in ng-repeat directly. Otherwise I can change values and get notification from $watchCollection.

A simplified example:

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.js">
    </script>
</head>
<body>
    <section ng-app="myApp" ng-controller = "TestController">
        <button ng-click = "pushToList()">Add number to list.</button>
        <button ng-click = "changeFirstElement()">Change first element.</button>
        <textarea ng-model = "log"></textarea>
        <ul>
            <li ng-repeat="item in list track by $index">
                <input ng-model="item"> Value: <span ng-bind="item"></span>
            </li>
        </ul>
    </section>
    <script>
        angular.module("myApp", [])
            .controller("TestController", function($scope){
                $scope.log = '';
                $scope.list = $scope.list = [1];

                $scope.pushToList = function() {
                    $scope.list.push(Math.random());
                }

                $scope.changeFirstElement = function() {
                    $scope.list[0] = Math.random();
                }

                $scope.$watchCollection(
                    'list',
                    function(currentValue, oldValue) {
                    $scope.log += [
                        'Current value:',
                        currentValue.toString(),
                        'Old value:',
                        oldValue ? oldValue.toString() : '',
                        '-----',
                        '',
                    ].join('\n')
        }
     )
        });
    </script>
</body>
</html>

$watchCollection does "see" when I make a change by calling $scope.list[0] = Math.random(); but when I use the input field changes are ignored, or "not seen" by $watchCollection. Why is this? And what can I do alternatively?

And I know I could use a deep $watch instead, but I'm interessted how to achieve this with $watchCollection. Also because performance is better if I understand it correctly (see this question).

EDIT:

Here is a plunkr.

When you click "Add number to list" the $watchCollection will see the changes and the current content of the array is writen to the textarea. When you change the first number by clicking on "Change first element" $watchCollection does see that there has been a change and again writes the current content on the array to the textarea. When you change the value with the input fields that are put there with ng-repeat that have the items of the array as ng-model. I expect that if I change a value in the input field that it would trigger the same behavior as when I click the "Change first element" butten: I expect that $watchCollection should see that there was a change and the function I registered should write the content of the array to the textarea. But this does not happen.

Community
  • 1
  • 1
Sjoerd222888
  • 3,228
  • 3
  • 31
  • 64

1 Answers1

1

The problem aren't in $watchCollection. ng-repeat creates scope for each child, so when you are typing in the input you change item property only in the ng-repeat child scope because item is primitive. If you had $scope.list=[{value:1}] you could change the value in parent scope changing value in child scope because list[0] and item share reference on the same object. But watchCollection still would not being fired because it detect only shallow changes.

Alex Soroka
  • 800
  • 9
  • 14