0

我发现 $scope.$watch 不会被触发,当 $watch 的目标设置为与当前持有的值相同的值时。

我创建了一个显示行为的示例 JSFiddle ( http://jsfiddle.net/VKHVq/ )。

在第一个输入字段 ( position_total ) 中输入任何值。total_before_discount会按应有的方式进行调整,total_before_discount $ watch 也会触发。由于折扣百分比为 0%,total_discount 将始终保持为 0。尽管如此,0 一直分配给 $scope.total_discount,但不幸的是,'total_discount' 上的监视没有被触发。我做错了什么还是这种行为是故意的?

对我来说,这种行为看起来不像预期的那样,因为我们在 $watch 函数中获得了 newValue 和 oldValue 并且可以在很多 angular.js $watch 示例中看到,建议测试 if (newValue === oldValue) {返回 }。

HTML

<div id="container" ng-controller="MyCtrl">    

    <div>Position total: <input type="number" ng-model="position_total"/>

    <div>Total before discount: {{total_before_discount}}</div>

    <div>Discount (in %): <input type="number" ng-model="discount"/>
    <div>Total discount: {{total_discount}}</div>

    <div>Total after discount: {{total_after_discount}}</div>

</div>

JS

var myApp = angular.module('myApp', ['ngAnimate']);

function MyCtrl($scope) {

    $scope.position_total = 0;
    $scope.total_before_discount = 0;
    $scope.discount = 0;
    $scope.total_discount = 0;
    $scope.total_after_discount = 0;

    calculatePositionTotal = function() {
        // Dummy method to simulate position calculation
        $scope.total_before_discount = $scope.position_total
    };

    calculateTotalDiscount = function() {
        var total_discount = ($scope.total_before_discount / 100) * $scope.discount;
        console.log('Going to set total_discount to ' + total_discount);
        $scope.total_discount = total_discount;   
    };

    calculateTotalAfterDiscount = function() {
        $scope.total_after_discount = $scope.total_before_discount - $scope.total_discount;
    };

    $scope.$watch('position_total', function (newValue, oldValue) {
        calculatePositionTotal();
    });

    $scope.$watch('total_before_discount', function (newValue, oldValue) {
        calculateTotalDiscount();
    });

    $scope.$watch('discount', function (newValue, oldValue) {
        calculateTotalDiscount();
    });

    $scope.$watch('total_discount', function (newValue, oldValue) {
        console.log('total_discount $watch triggered...');
        calculateTotalAfterDiscount();
    });

}
4

2 回答 2

4

文档说:

仅当来自当前 watchExpression 的值与上一次调用 watchExpression 的值不相等时才调用侦听器(初始运行除外,见下文)。

所以这是预期的行为。

于 2013-11-10T14:07:00.667 回答
2

total_discount 的初始值为 0,当您第一次设置手表时,它会被 oldValue 和 newValue as 触发0。之后手表不会触发,直到 total_discount 的值发生变化。如果您继续为其分配值 0,则手表不会触发。

Watch 只会在值更改时触发,除非在文档中提到的极少数情况下

在观察者注册到作用域后,监听器 fn 被异步调用(通过 $evalAsync)来初始化观察者。在极少数情况下,这是不可取的,因为当 watchExpression 的结果没有改变时调用了侦听器。要在侦听器 fn 中检测这种情况,您可以比较 newVal 和 oldVal。如果这两个值相同(===),则由于初始化而调用了侦听器。

于 2013-11-10T14:06:27.363 回答