假设我想要一个指令,它接受用户输入的内容并将其变为小写。
所以我想出了一个像这样的指令(在这个Plunker http://plnkr.co/edit/jnE3s8MRr1tFCX0WVYel?p=preview中):
app.directive('lowerCaseInput', function() {
return {
restrict: 'E',
template:'<input ng-model="vm.input" />',
scope: {},
require: ['ngModel', 'lowerCaseInput'],
controller:function() {},
link: function(scope, el, attrs, ctrls) {
var ngModel = ctrls[0], vm = ctrls[1];
ngModel.$render = render;
// view-> model
ngModel.$parsers.push(function(value) {
return toLowerCase(value);
});
// model->view
ngModel.$formatters.push(function(value) {
return value;
});
function render() {
vm.input = ngModel.$viewValue;
}
// view -> model && model-> view
function toLowerCase(value) {
return value && value.toLowerCase();
}
scope.$watch('vm.input', function(newVal, oldVal) {
if(newVal !== oldVal)
ngModel.$setViewValue(newVal);
});
},
controllerAs: 'vm'
}
})
但是,如您在演示中所看到的,因为从未触发setViewValue,所以模型值不会在初始遍历中得到反映(变成小写)。在这种情况下,我确实希望指令根据某些规则更改模型,是否应该遵循一般方法?
此外,我想避免在用户与之实际交互之前将控件变为脏的,因此即使我确实调用了$ setViewValue并导致了$ parsers管道,我也希望它能够意识到用户实际上并没有与之交互(因此将其保留为$ pristine)。
这可能吗?如果是这样,有什么最佳实践(例如可以从$ format调用$ setViewValue吗–直接覆盖ngModel吗?
最佳答案
以下解决方案适用于我(使用Angular 1.4)
在更新viewvalue y之前,只需保存对$ setDirty函数的引用,然后在ngModelCtrl中将其替换为空函数。设置viewvalue之后,我恢复了原始功能。
var tmp = ngModelController.$setDirty;
ngModelController.$setDirty = angular.noop;
ngModelController.$setViewValue(value);
ngModelController.$setDirty = tmp;
这对我有用,因为我能够在自定义指令中设置默认值,并且输入字段和表单控制器都保持$ pristine。
当心:我没有使用自定义的ng-model-options。我没有尝试过,但是我确定如果您使用自定义防抖动超时,则该解决方案将无法为您服务,但是我认为可以在防抖动时间到期后调用
ngModelController.$setDirty = tmp;
行。