【问题标题】:AngularJS how do I watch $viewValue instead of ngModel?AngularJS 如何观看 $viewValue 而不是 ngModel?
【发布时间】:2014-09-30 01:40:05
【问题描述】:

我在输入上使用 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 时立即禁用按钮,而不是在等待完全去抖动秒后。我最好的猜测是这意味着在$viewValue 上加上$watch,但我不知道如何在指令中找到它。

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

   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');
            });
        });
    }

【问题讨论】:

    标签: javascript angularjs watch


    【解决方案1】:

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

    您想像这样使用$viewChangeListeners 而不是$watch(您可能需要推送到$formatters,这取决于去抖的工作方式):

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

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

    【讨论】:

    • $viewChangeListeners 仅在 $modelValue 更改时触发。当ngModel 无效时,$modelValue 变为undefined 并且$viewChangeListeners 不再触发。但是,$viewValue 仍会在每次更改时进行更新。有什么建议如何观看$viewValue
    【解决方案2】:

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

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

    见:https://docs.angularjs.org/api/ng/directive/ngModelOptions

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

    【讨论】:

    • 解决我的问题的好方法
    【解决方案3】:

    如果标签具有 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
                        }
                    );
                }
            }
        })();
    

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多