我有一些自定义验证代码,其中包括一个 $formatter。(为了正确起见,我以便士存储货币,但以磅.便士显示。)
如果用户在输入中键入“10”(这是一个有效值),则在他们移动到下一个字段后输入仍然显示“10”。
我希望它显示 10.00 以保持一致性。
如果模型将值更改为 1000,那么格式化程序将使字段显示为“10.00”。
我希望格式化程序在 field.blur() 上运行(只要输入有效)。
我的问题是,如果我将模型值从 10 更改为 10,则没有任何变化是可以理解的,因此不会重新渲染该字段。
代码:
var CURRENCY_REGEXP = /^\-?\d+(\.?\d?\d?)?$/;
app.directive('currency', function() {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
if (CURRENCY_REGEXP.test(viewValue)) {
// it is valid
ctrl.$setValidity('currency', true);
console.log("valid");
return viewValue * 100;
} else if (viewValue === '') {
return 0;
} else {
// it is invalid, return undefined (no model update)
ctrl.$setValidity('currency', false);
console.log("invalid");
return undefined;
}
});
ctrl.$formatters.push(function(modelValue) {
if (modelValue === 0) { // we're using integer pence, so this is safe
return '';
}
return (modelValue / 100).toFixed(2);
});
}
};
});
PS 这与 Angular 的内置“货币”无关。
更新:根据安迪的回答,我添加了一个“renderOnBlur”指令。它被调用,但调用渲染方法不会重新渲染输入。即“10”保持为“10”,而不是根据需要更改为“10.00”。
(当这些字段中的模型值发生变化时,它们会以 2 位小数正确呈现。)
Andy 提到的页面http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController说你必须$render
自己实现。这看起来很奇怪,因为当模型值更改时,输入已经正确呈现。
app.directive('renderOnBlur', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, elm, attrs, ctrl) {
elm.bind('blur', function() {
console.log('rendering ctrl', ctrl);
ctrl.$render();
});
}
};
});
PS我不知道是什么restrict: 'A',
- 这是最糟糕的真正的货物崇拜节目。似乎有require: 'ngModel',
必要填充ctrl
参数。
受@Dan Doyen 的回答启发,我将其改写为:
app.directive('renderOnBlur', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, elm, attrs, ctrl) {
elm.bind('blur', function() {
var viewValue = ctrl.$modelValue;
for (var i in ctrl.$formatters) {
viewValue = ctrl.$formatters[i](viewValue);
}
ctrl.$viewValue = viewValue;
ctrl.$render();
});
}
};
});
这样做的好处是对于任何 $formatter 都是通用的,而不是像 Dan 的回答那样重复格式化程序代码。