如何在设置去抖动的情况下立即设置 ngModel 对输入的$viewValue



假设,我想对文本输入应用屏蔽函数。它可以对输入的电话号码进行适当的风格化(例如,对于输入5553334444,它将输出(555) 333-4444),也可以只是简单地将输入控件中的值大写。

我知道的方法使用ngModel控制器(通过require: "ngModel"),并在$parser函数中设置新的大写$viewValue

ngModel.$parsers.unshift(function(val){
  var uppercase = val && val.toUpperCase();
  if (uppercase !== val){
    ngModel.$setViewValue(uppercase);
    ngModel.$render();
  }
  return uppercase;
});

但现在,假设我想使用ng-model-options="{debounce: 400}",因为我不想太快地触发模型的变化:

<input ng-model="foo" ng-model-options="{debounce: 400}"
       ng-change="doBackendQuery(foo)"
       uppercase>

在上面的例子中,我不想太快地触发doBackendQuery,因为它会进行HTTP调用。debounce可以防止这种情况发生,但它也可以防止uppercase指令立即执行,从而导致用户看到小写文本。

Q:如何编写uppercase指令来立即更改$viewValue,而无需等待debounce

(注意:我不想对底层DOM元素进行假设——这与DOM不可知的ng-model的想法背道而驰)

plunker

一个破解的解决方案(未经测试):

<input ng-model="foo" ng-model-options="{debounce: 400}"
   ng-change="doBackendQuery(foo)"
   uppercase style="text-transform: uppercase;">

您还可以更改uppercase指令以自动设置该样式,或者使用css:

input[uppercase] {
    text-transform: uppercase;
}

这对我有效:

app.directive('capitalize', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attrs, modelCtrl) {
            element.on('input', function() {
                var capitalized = element.val().toUpperCase();
                element.val(capitalized);
                modelCtrl.$setViewValue(capitalized);
            });
            modelCtrl.$parsers.push(function(value) {
                return value.toUpperCase();
            });
        }
    };
});

(function(){
    angular
        .module('example', [])
        .directive('uppercase', [function(){
            return {
                restrict: 'A',
                require: 'ngModel',
                link: function(scope, iElem, iAttrs, ngModel){
                    iElem.on('input', function(){
                        var elem = angular.element(this),
                            valOrigin = elem.val();
                        
                        val = toUpperCase(valOrigin);
                        elem.val( val );
                        ngModel.$viewValue = toLowerCase(valOrigin);
                    });
                    ngModel.$parsers.push(function(value){
                        value = toLowerCase(value);
                        return value;
                    });
                    ngModel.$formatters.push(function(value){
                        value = toUpperCase(value);
                        return value;
                    });
                    function toLowerCase(value){
                        return (value + '').toLowerCase();
                    }
                    function toUpperCase(value){
                        return (value + '').toUpperCase();
                    }
                }
            }
        }])
        .controller('ExampleController', [function() {
            
            var vc = this;
            vc.user = {
                name: 'let' start!'
            };
        }]);
    angular
        .bootstrap(document, ['example']);
})();
<script src="https://code.angularjs.org/1.4.7/angular.min.js"></script>
<div ng-controller="ExampleController as example">
  <form name="userForm">
    <label>Name:
      <input type="text" name="userName" uppercase ng-model="example.user.name" ng-model-options="{debounce: 500}" />
    </label>
    <p>Name: <span>{{ example.user.name }}</span></p>
  </form>
</div>

最新更新