使用angularjs保留光标位置

以下代码片段执行我想要的input ,即,它删除所有非字母数字字符,转换为大写,并保留光标位置。

 element = $(element); element.keyup(function() { var x = element.val(); var y = x && x.toUpperCase().replace(/[^AZ\d]/g, ''); if (x===y) return; var start = this.selectionStart; var end = this.selectionEnd + y.length - x.length; element.val(y); this.setSelectionRange(start, end); }); 

我把这个片段放在一个指令的link中,它主要起作用….

问题是angular模型在应用更改之前看到了值。 我试图谷歌如何使用$apply$digest或其他什么,但没有任何效果。

(实际上,我以某种方式管理它,但随后内容被重新渲染,我失去了位置。我无法重现它,但它还不够好,无论如何。)

这样做的方法

  • 输入只清理一次
  • 然后输入的ngChange只被触发一次

是使用ngModelController提供的$parsers数组。 它被设计为影响模型值的位置(通过其返回值),但它也可以用作输入事件的监听器。

 app.directive('cleanInput', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModelController) { var el = element[0]; function clean(x) { return x && x.toUpperCase().replace(/[^AZ\d]/g, ''); } ngModelController.$parsers.push(function(val) { var cleaned = clean(val); // Avoid infinite loop of $setViewValue <-> $parsers if (cleaned === val) return val; var start = el.selectionStart; var end = el.selectionEnd + cleaned.length - val.length; // element.val(cleaned) does not behave with // repeated invalid elements ngModelController.$setViewValue(cleaned); ngModelController.$render(); el.setSelectionRange(start, end); return cleaned; }); } } }); 

但是,我不确定$parsers这种用法是否有点像黑客攻击。 该指令可用作:

  

或者如果你想要一个ngChange函数:

  

这可以在http://plnkr.co/edit/dAJ46XmmC49wqTgdp2qz?p=preview上看到。

需要的主要内容是:

  • 要求ngModelController能够调用其方法并获取/设置其值。 特别…

  • 用call替换call element.val(y)

     ngModelController.$setViewValue(y); ngModelController.$render(); 

    我想我应该承认,我不完全确定ngModelController的内部工作原理,以了解为什么这是必要的。

  • 可选,但是通过element.val()获取视图中的现有值可以通过以下方式完成:

     ngModelController.$viewValue; 

    这至少与设置视图值的方式更加一致。

  • 再次是可选的,但是监听input事件会使接口变得更好,因为它似乎在keyup事件之前触发了一点,所以你没有获得未处理输入的闪存。

  • 添加到$parsers数组来处理输入似乎会停止为未处理的输入版本触发任何ngChange回调。

     ngModelController.$parsers.push(function(val) { // Return the processed value }) 

将所有这些放在一起作为自定义指令:

 app.directive('cleanInput', function() { return { require: 'ngModel', link: function(scope, element, attrs, ngModelController) { function clean(x) { return x && x.toUpperCase().replace(/[^AZ\d]/g, ''); } ngModelController.$parsers.push(function(val) { return clean(val); }) element.on('input', function() { var x = ngModelController.$viewValue; var y = clean(x); var start = this.selectionStart; var end = this.selectionEnd + y.length - x.length; ngModelController.$setViewValue(y); ngModelController.$render(); this.setSelectionRange(start, end); }); } } }); 

可以用作:

  

或者如果你想要一个ngChange函数:

  

并在http://plnkr.co/edit/FymZ8QEKwj2xXTmaExrH?p=preview上看到了

编辑:添加关于$parsers数组的部分。 我应该承认,@ Engineer的回答让我想到了它。