以下代码段执行我想要的input
,即删除所有非字母数字字符,转换为大写,并保留光标位置。
element = $(element);
element.keyup(function() {
var x = element.val();
var y = x && x.toUpperCase().replace(/[^A-Z\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
模型在应用更改之前看到值。我尝试了Google如何使用$apply
或$digest
或其他任何内容,但没有任何效果。
(实际上,我以某种方式管理它,但随后内容被重新渲染,我失去了位置。我无法重现它,但它还不够好,无论如何。)
答案 0 :(得分:21)
这样做的方法
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(/[^A-Z\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
的这种用法是否有点像黑客。该指令可用作:
<input type="text" clean-input ng-model="name">
或者如果您想要ngChange
功能:
<input type="text" clean-input ng-model="name" ng-change="onChange()">
中看到
答案 1 :(得分:1)
所需要的主要内容是:
要求ngModelController
能够调用其方法并获取/设置其值。具体地说...
将来电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(/[^A-Z\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);
});
}
}
});
可以用作:
<input type="text" clean-input ng-model="name">
或者如果您想要ngChange
功能:
<input type="text" clean-input ng-model="name ng-change="onChange()">
并在http://plnkr.co/edit/FymZ8QEKwj2xXTmaExrH?p=preview
的行动中看到了编辑:添加关于$parsers
数组的部分。我应该承认,正是@ Engineer的答案让我想到了它。