AngularJS如何观看$ viewValue而不是ngModel?

时间:2014-08-06 23:27:26

标签: javascript angularjs watch

我在输入上使用debounce:

<input type="text"
     ng-model="model.qty"
     ng-model-options="{ debounce : 1000 }"
     min="{{model.min}}" max="{{model.max}}" step="1"
     qty-input validate-model-setting>

我有一个指令来处理禁用此输入的增量按钮和减量按钮:

app.directive('qtyInput', function() {
    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, element, attrs, ngModelCtrl) {
            scope.$watch(attrs.ngModel, function(n, o) {
                var val = parseInt(n);
                if(!isNaN(val)) {
                    if(val + 1 > model.max) {
                        scope.quantityIncDisabled = true;
                    } else {
                        scope.quantityIncDisabled = false;
                    }
                    if(val - 1 < model.min) {
                        scope.quantityDecDisabled = true;
                    } else {
                        scope.quantityDecDisabled = false;
                    }
                }
            });
        }
    }
});

问题是,该指令上的手表正在查看模型。我需要它来查看$viewValue。这是因为,由于去抖动,在输入中输入和使用递增/递减按钮之间存在竞争条件。例如,您可以在输入达到1(最小值)后反复单击减量按钮1秒钟,然后在去抖动结束后,减量按钮将被禁用。相反,我希望在输入达到1时立即禁用该按钮,而不是在等待完全去抖秒之后。我最好的猜测是,这意味着在$watch上加$viewValue,但我不知道如何在指令中找到它。

作为参考,按钮本身通过更改输入的值然后触发输入来避免竞争条件,这使得去抖动在键入输入和使用按钮时都是流畅的。

   link: function(scope, element, attrs) {
        element.bind('click', function() {
            $timeout(function() {
                var input = element.parent().find('input');
                var changingTo = parseInt(input[0].value) + parseInt(scope.inc);
                if(scope.inc < 0 || isNaN(changingTo)) {
                    var min = parseInt(input[0].min);
                    if(isNaN(changingTo)) {
                        changingTo = min;
                    } else if(changingTo < min) {
                        return;
                    }
                } else {
                    var max = parseInt(input[0].max);
                    if(changingTo > max) {
                        return;
                    }
                }
                input[0].value = String(changingTo);
                input.trigger('input');
            });
        });
    }

4 个答案:

答案 0 :(得分:4)

文档的答案是:https://code.angularjs.org/1.2.19/docs/api/ng/type/ngModel.NgModelController

您希望使用$viewChangeListeners代替$watch,因此根据debounce的工作方式,您可能需要推送到$formatters

ngModelCtrl.$viewChangeListeners.push(function(){
  var val = parseInt(ngModelCtrl.$viewValue);
  if(!isNaN(val)) {
    ...
  }
});

虽然我还没有使用去抖动选项,所以我不知道这是否能解决您的问题,但这就是您观看viewValue的方式。

答案 1 :(得分:2)

如果标签具有ng-model和match属性,这将观察ngModelController的$ viewValue。也可以观察其他ngModelController $ viewValues,就像在具有许多输入指令的表单中一样。

    (function () {
        'use strict';

        angular
            .module('app.commons')
            .directive('match', MatchValidator);

        function MatchValidator() {
            return {
                require: 'ngModel',
                link: LinkFunction
            };

            function LinkFunction(scope, element, attrs, ngModel) {
                scope.$watch(function(){
                        return ngModel.$viewValue;
                    }, 
                    function(newValue, oldValue){
                        // do something
                    }
                );
            }
        }
    })();

答案 2 :(得分:2)

观看$ viewValue的另一种解决方案是允许无效的ng-model更新,然后你可以改为观看模型。

ng-model-options="{allowInvalid: true}"

请参阅:https://docs.angularjs.org/api/ng/directive/ngModelOptions

这不是这个问题的直接答案,但我认为它将有助于人们访问此主题的许多用例。

答案 3 :(得分:0)

就个人而言,我不得不使用$ formatters来避免等待去抖。