在输入中过滤 ng-model

Posted

技术标签:

【中文标题】在输入中过滤 ng-model【英文标题】:filters on ng-model in an input 【发布时间】:2013-01-03 09:17:08 【问题描述】:

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

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

ng-model='tags | lowercase | no_spaces'

我考虑创建自己的指令,但向$parsers$formatters 添加函数并没有更新输入,只更新了带有ng-model 的其他元素。

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

我实际上是在尝试创建类似于 *** 上的“标签”功能。

【问题讨论】:

看看在 ng-change 中使用 $timeout(...,0) 是否有帮助:***.com/questions/12176925/… 【参考方案1】:

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

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

【讨论】:

这正是我想要的。原来我已经在使用 angularjs 1.1.1 @Valentyn,您的解决方案适用于我在上面的评论中引用的 SO 问题。谢谢。 ***.com/questions/12176925/… 此解决方案可能会产生不良副作用,请参阅下面的其他答案,您应该为此使用指令 $watch 重新分配范围变量会强制再次调用侦听器。在简单的情况下(您的过滤器是幂等的),您最终会在每次修改时执行两次过滤器。【参考方案2】:

我相信 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 指令。

这种方法的优点是 2 倍:

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

【讨论】:

我确信棘手的部分是 modelCtrl.$setViewValue(transformedInput); modelCtrl.$render(); 有用的是链接到文档:docs.angularjs.org/api/ng.directive:ngModel.NgModelController “保护”我的唯一想法的一个词是范围属性不仅可以从视图和我的方式覆盖这个。所以我认为这取决于实际情况如何修改范围。 您的示例中的“modelCtrl”指的是什么? 你从哪里得到 inputValue? @GSto modelCtrl 是指令所需的控制器。 (require 'ngModel') 每次输入无效字符时光标都会跳到文本域的末尾,尝试写'world'并修改为'HeLLo world'!【参考方案3】:

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

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

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

【讨论】:

但是如果你想让它正确更新,你需要一个 $watch 。 这只执行一次。并且添加到手表不是正确的解决方案,因为它甚至在最初也允许模型变得无效 - 正确的解决方案是添加到模型的 $parsers。 您不必喜欢我的回答,但这并不意味着它是错误的。在投反对票之前检查一下你的自我。【参考方案4】:

我也遇到过类似的问题,用过

ng-change="handler(objectInScope)" 

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

$scope.objectInScope = myObject; 

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

【讨论】:

【参考方案5】:

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

有关更多详细信息,包括指向 jsfiddle 的链接,请参阅 this other answer。

【讨论】:

【参考方案6】:

你可以试试这个

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

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

);

【讨论】:

【参考方案7】:

如果您正在执行复杂的异步输入验证,那么将 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) )
  ;

)();

【讨论】:

【参考方案8】:

如果您使用只读输入字段,您可以使用带有过滤器的 ng-value。

例如:

ng-value="price | number:8"

【讨论】:

+1 这可能不是对所提出问题的确切答案,但包括它对情况可能略有不同的其他人有所帮助。

以上是关于在输入中过滤 ng-model的主要内容,如果未能解决你的问题,请参考以下文章

正确的输入——过滤器模式

过滤 dataTables.net,不包含过滤框输入

在输入元素中使用 angularjs 过滤器

如何在数据表中使用输入字段添加最小和最大范围过滤器?

用Javascript如何实现在输入框中输入汉字拼音的首字母动态过滤相应的汉字??

如何使用 vue/vuex 从输入中过滤数据?