如何$观察角度的多变量变化

azt*_*ack 84 angularjs

如何$scope.$watch在Angular中使用多个变量,并在其中一个变化时触发回调.

$scope.name = ...
$scope.age = ...
$scope.$watch('???',function(){
    //called when name or age changed
})
Run Code Online (Sandbox Code Playgroud)

sto*_*ofl 120


UPDATE

Angular现在提供两种范围方法$ watchGroup(自1.3起)和$ watchCollection.@blazemonger和@kargold已经提到过这些.


这应该独立于类型和值:

$scope.$watch('[age,name]', function () { ... }, true);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您必须将第三个参数设置为true.

字符串连接'age + name'将在以下情况下失败:

<button ng-init="age=42;name='foo'" ng-click="age=4;name='2foo'">click</button>
Run Code Online (Sandbox Code Playgroud)

在用户单击按钮之前,监视的值将是42foo(42+ foo)并且在单击42foo(4+ 2foo)之后.因此不会调用监视功能.因此,如果无法确保,则最好使用数组表达式,这样的情况不会出现.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <link href="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.css" rel="stylesheet" />
        <script src="//cdn.jsdelivr.net/jasmine/1.3.1/jasmine.js"></script>
        <script src="//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>
Run Code Online (Sandbox Code Playgroud)

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

PS:

正如@reblace在评论中所述,当然可以访问这些值:

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

  • 如果你想要观察的变量都是简单的原语,那么`$ watchCollection`可能更合适. (2认同)

Flo*_*n F 43

$scope.$watch('age + name', function () {
  //called when name or age changed
});
Run Code Online (Sandbox Code Playgroud)

  • 还要确保在这种情况下不使用angular传递给回调的`newValue`和`oldValue`参数,因为它们将是结果连接而不仅仅是已更改的字段. (4认同)
  • 对于找到同一问题答案的任何人 - 我的答案是不正确的,这个答案是对的. (3认同)
  • 由于JS将它们称为字符串,因此这将起作用.顺便说一句,答案是正确的. (2认同)

kar*_*old 8

Angular 1.3专门为此目的提供了$ watchGroup:

https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watchGroup

这似乎提供了与表达式数组上的标准$ watch相同的最终结果.我喜欢它,因为它使代码中的意图更清晰.


Ema*_*a.H 6

有很多方法可以观察多个值:

//angular 1.1.4
$scope.$watchCollection(['foo', 'bar'], function(newValues, oldValues){
    // do what you want here
});
Run Code Online (Sandbox Code Playgroud)

或更新的版本

//angular 1.3
$scope.$watchGroup(['foo', 'bar'], function(newValues, oldValues, scope) {
  //do what you want here
});
Run Code Online (Sandbox Code Playgroud)

阅读官方文档了解更多信息:https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope


Hen*_*k N 6

没人提到这个显而易见的事实:

var myCallback = function() { console.log("name or age changed"); };
$scope.$watch("name", myCallback);
$scope.$watch("age", myCallback);
Run Code Online (Sandbox Code Playgroud)

这可能意味着少一些民意调查.如果你同时观察name + age(为此)和name(其他地方),那么我假设Angular会有效地查看name两次以查看它是否脏.

通过名称使用回调而不是内联它可以说更具可读性.特别是如果你能给它一个比我的例子更好的名字.

如果您需要,您可以通过不同方式观察价值观:

$scope.$watch("buyers", myCallback, true);
$scope.$watchCollection("sellers", myCallback);
Run Code Online (Sandbox Code Playgroud)

$watchGroup 如果你可以使用它是很好的,但据我所知,它不会让你将组成员视为集合或具有对象相等性.

如果在同一个回调函数调用中需要两个表达式的旧值和新值,那么可能一些其他提出的解决方案更方便.