过滤输入中的ng-model

时间:2013-01-19 22:38:43

标签: angularjs angularjs-filter dom-manipulation angularjs-ng-model

我有一个文本输入,我不想让用户使用空格,所有输入的内容都会变成小写。

我知道我不允许在ng-model上使用过滤器,例如。

ng-model='tags | lowercase | no_spaces'

我查看了创建自己的指令,但向$parsers$formatters添加功能并未更新输入,只更新了其他ng-model元素。

如何更改我正在输入的输入?

我实际上是在尝试创建'tags'功能,就像StackOverflow上的功能一样。

8 个答案:

答案 0 :(得分:203)

我认为AngularJS输入和ngModel指令的意图是无效输入永远不会在模型中结束。该模型应始终有效。拥有无效模型的问题在于我们可能会让观察者根据无效模型触发并采取(不适当的)操作。

正如我所看到的,这里适当的解决方案是插入$parsers管道并确保无效输入不会进入模型。我不确定你是如何尝试使用$parsers来处理事情或者究竟什么不适合你,但这是一个简单的指令来解决你的问题(或至少我对问题的理解):

app.directive('customValidation', function(){
   return {
     require: 'ngModel',
     link: function(scope, element, attrs, modelCtrl) {

       modelCtrl.$parsers.push(function (inputValue) {

         var transformedInput = inputValue.toLowerCase().replace(/ /g, ''); 

         if (transformedInput!=inputValue) {
           modelCtrl.$setViewValue(transformedInput);
           modelCtrl.$render();
         }         

         return transformedInput;         
       });
     }
   };
});

一旦宣布上述指令,就可以这样使用:

<input ng-model="sth" ng-trim="false" custom-validation>

正如@Valentyn Shybanov提出的解决方案一样,如果我们想要在输入的开头/结尾处禁止空格,我们需要使用ng-trim指令。

这种方法的优点是双重的:

  • 无效值不会传播到模型
  • 使用指令可以轻松地将此自定义验证添加到任何输入而无需一遍又一遍地重复观察者

答案 1 :(得分:28)

我建议观看模型值并在chage上更新它:http://plnkr.co/edit/Mb0uRyIIv1eK8nTg3Qng?p=preview

唯一有趣的问题是空格:在AngularJS 1.0.3 ng-model上输入会自动修剪字符串,因此如果在结尾或开始时添加空格,它不会检测到模型被更改(因此空格不会自动我的代码删除了)。但是在1.1.1中有&#39; ng-trim&#39;允许禁用此功能的指令(commit)。因此,我决定使用1.1.1来实现您在问题中描述的确切功能。

答案 2 :(得分:23)

此问题的解决方案可能是在控制器端应用过滤器:

$scope.tags = $filter('lowercase')($scope.tags);

不要忘记将$filter声明为依赖。

答案 3 :(得分:5)

如果您使用的是只读输入字段,则可以将ng-value与过滤器一起使用。

例如:

ng-value="price | number:8"

答案 4 :(得分:4)

使用一个指令来添加$ formatters和$ parsers集合,以确保在两个方向上执行转换。

有关详细信息,请参阅this other answer,其中包含指向jsfiddle的链接。

答案 5 :(得分:3)

我遇到了类似的问题并使用了

ng-change="handler(objectInScope)" 

在我的处理程序中,我调用objectInScope的方法来正确修改自身(粗略输入)。在控制器中我已经启动了某个地方

$scope.objectInScope = myObject; 

我知道这不会使用任何花哨的过滤器或观察者...但它很简单,效果很好。唯一的缺点是objectInScope是在对处理程序的调用中发送的......

答案 6 :(得分:1)

如果您正在进行复杂的异步输入验证,那么将ng-model作为自定义类的一部分用自己的验证方法进行抽象可能是值得的。

https://plnkr.co/edit/gUnUjs0qHQwkq2vPZlpO?p=preview

<强> HTML

<div>

  <label for="a">input a</label>
  <input 
    ng-class="{'is-valid': vm.store.a.isValid == true, 'is-invalid': vm.store.a.isValid == false}"
    ng-keyup="vm.store.a.validate(['isEmpty'])"
    ng-model="vm.store.a.model"
    placeholder="{{vm.store.a.isValid === false ? vm.store.a.warning : ''}}"
    id="a" />

  <label for="b">input b</label>
  <input 
    ng-class="{'is-valid': vm.store.b.isValid == true, 'is-invalid': vm.store.b.isValid == false}"
    ng-keyup="vm.store.b.validate(['isEmpty'])"
    ng-model="vm.store.b.model"
    placeholder="{{vm.store.b.isValid === false ? vm.store.b.warning : ''}}"
    id="b" />

</div>

<强>码

(function() {

  const _ = window._;

  angular
    .module('app', [])
    .directive('componentLayout', layout)
    .controller('Layout', ['Validator', Layout])
    .factory('Validator', function() { return Validator; });

  /** Layout controller */

  function Layout(Validator) {
    this.store = {
      a: new Validator({title: 'input a'}),
      b: new Validator({title: 'input b'})
    };
  }

  /** layout directive */

  function layout() {
    return {
      restrict: 'EA',
      templateUrl: 'layout.html',
      controller: 'Layout',
      controllerAs: 'vm',
      bindToController: true
    };
  }

  /** Validator factory */  

  function Validator(config) {
    this.model = null;
    this.isValid = null;
    this.title = config.title;
  }

  Validator.prototype.isEmpty = function(checkName) {
    return new Promise((resolve, reject) => {
      if (/^\s+$/.test(this.model) || this.model.length === 0) {
        this.isValid = false;
        this.warning = `${this.title} cannot be empty`;
        reject(_.merge(this, {test: checkName}));
      }
      else {
        this.isValid = true;
        resolve(_.merge(this, {test: checkName}));
      }
    });
  };

  /**
   * @memberof Validator
   * @param {array} checks - array of strings, must match defined Validator class methods
   */

  Validator.prototype.validate = function(checks) {
    Promise
      .all(checks.map(check => this[check](check)))
      .then(res => { console.log('pass', res)  })
      .catch(e => { console.log('fail', e) })
  };

})();

答案 7 :(得分:0)

你可以试试这个

$scope.$watch('tags ',function(){

    $scope.tags = $filter('lowercase')($scope.tags);

});