How to $watch multiple variable change in angular [duplicate]


UPDATE

Angular offers now the two scope methods $watchGroup (since 1.3) and $watchCollection. Those have been mentioned by @blazemonger and @kargold.


This should work independent of the types and values:

$scope.$watch('[age,name]', function () { ... }, true);

You have to set the third parameter to true in this case.

The string concatenation 'age + name' will fail in a case like this:

<button ng-init="age=42;name="foo"" ng-click="age=4;name="2foo"">click</button>

Before the user clicks the button the watched value would be 42foo (42 + foo) and after the click 42foo (4 + 2foo). So the watch function would not be called. So better use an array expression if you cannot ensure, that such a case will not appear.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <link href="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet" />
        <script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
        <script src="https://cdn.jsdelivr.net/jasmine/1.3.1/jasmine-html.js"></script>
        <script src="http://code.angularjs.org/1.2.0-rc.2/angular.js"></script>
        <script src="http://code.angularjs.org/1.2.0-rc.2/angular-mocks.js"></script>
        <script>

angular.module('demo', []).controller('MainCtrl', function ($scope) {

    $scope.firstWatchFunctionCounter = 0;
    $scope.secondWatchFunctionCounter = 0;

    $scope.$watch('[age, name]', function () { $scope.firstWatchFunctionCounter++; }, true);
    $scope.$watch('age + name', function () { $scope.secondWatchFunctionCounter++; });
});

describe('Demo module', function () {
    beforeEach(module('demo'));
    describe('MainCtrl', function () {
        it('watch function should increment a counter', inject(function ($controller, $rootScope) {
            var scope = $rootScope.$new();
            scope.age = 42;
            scope.name="foo";
            var ctrl = $controller('MainCtrl', { '$scope': scope });
            scope.$digest();

            expect(scope.firstWatchFunctionCounter).toBe(1);
            expect(scope.secondWatchFunctionCounter).toBe(1);

            scope.age = 4;
            scope.name="2foo";
            scope.$digest();

            expect(scope.firstWatchFunctionCounter).toBe(2);
            expect(scope.secondWatchFunctionCounter).toBe(2); // This will fail!
        }));
    });
});


(function () {
    var jasmineEnv = jasmine.getEnv();
    var htmlReporter = new jasmine.HtmlReporter();
    jasmineEnv.addReporter(htmlReporter);
    jasmineEnv.specFilter = function (spec) {
        return htmlReporter.specFilter(spec);
    };
    var currentWindowOnload = window.onload;
    window.onload = function() {
        if (currentWindowOnload) {
            currentWindowOnload();
        }
        execJasmine();
    };
    function execJasmine() {
        jasmineEnv.execute();
    }
})();

        </script>
    </head>
    <body></body>
</html>

http://plnkr.co/edit/2DwCOftQTltWFbEDiDlA?p=preview

PS:

As stated by @reblace in a comment, it is of course possible to access the values:

$scope.$watch('[age,name]', function (newValue, oldValue) {
    var newAge  = newValue[0];
    var newName = newValue[1];
    var oldAge  = oldValue[0];
    var oldName = oldValue[1];
}, true);

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)