使用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的回答让我想到了它。