在一个指令中,$ watch触发两次将newValue恢复为原来的$ watch值射击值

时间:2013-04-04 09:48:42

标签: angularjs angularjs-directive angularjs-scope

我很确定我做错了,因为我对角度的经验不多。 可能答案已经在stackoverflow中的某个地方了,我并没有问(谷歌搜索)正确的问题。

我有这个非常简单的指令。它只是一个有四种状态的跨度,我想在每次点击跨度时改变。 每次点击都会使状态向前进行,然后循环返回。每个州都有不同的CSS类。 我希望每当指令的值发生变化时,父模型上的值都会发生变化(因此隔离范围声明中的" ="对吧?)。

我对值进行了监视以更改类,以便每次值更改时都会更新css类。

现在,问题在于,当我点击时,会使用newValue触发监视,但随后再次触发,newValue等于点击前的值。

我认为这与脏检查和父控制器模型的连接有关,但是,这样做的正确角度方法是什么?和/或有更好,更有棱角的方式获得相同的结果?

这里是指令:

.directive('square', function() {
    return {
        restrict: 'E',
        transclude: true,
        scope : {
            value : '=',
        },
        link: function(scope, elm, attrs, ctrl) {

            scope.valueToClass = function(value) {
                var result = 'square-empty';
                    if (value == '1') {
                        result = 'square-temp';
                    } else if (value == '2') {
                        result = 'square-confirmed';
                    } else if (value == '3') {
                        result = 'square-critical';
                    }
                return 'block-'+result;
            }

            scope.$watch('value', function(newValue, oldValue) {
                scope.blockClass = scope.valueToClass(newValue)

            }, true);

        },
        controller: function($scope, $element, $attrs) {
            $scope.changeValue = function() {
                $scope.value = ($scope.value+1) % 4;
            }
        },
        template : '<span class="{{blockClass}}"  ng-click="changeValue();">'+'</span>',
        replace: true
    };
});

此处>>the fiddle<<

3 个答案:

答案 0 :(得分:3)

这是因为您正在观察$ scope.block数组的原始值(整数)的变化。

在控制器中试试

 $scope.block = [{value: 3}, {value: 2}, {value: 1}, {value: 0}];

然后在视图中:

<square ng-repeat="squareValue in block" value="squareValue.value"></square>

(Englsh不是我的第一语言,对于简短的回答很抱歉)

答案 1 :(得分:3)

您不应该使用原始值来观察更改,因为由于javascript中的原型继承,子范围会超出父范围值。请查看非常好的文章,其中解释了所有原因。 https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance

答案 2 :(得分:0)

另一个可能对某人有帮助的答案是,您需要检查newVal是否已更改,newVal将始终传入,因此您需要检查它是否相同,即:

$scope.$watch('someProperty', function(newVal, oldVal) {
    if (newVal !== oldVal) {
        // do something
    }
});

我发现这解决了我的$ watch监听器过早触发的问题,无论scope属性是否是原始的,即我的属性是一个整数$ scope.menuId。