我的设置: Angular 1.4.4
我有一个简单的表单,如下所示:
<div ng-controller="MyCtrl3">
<datepick ng-model="model.carA" foo3="model.carB"></datepick>
<datepick ng-model="model.carB" foo3="model.carA"></datepick>
<pre> {{ model | json }} </pre>
</div>
datepick
指令如下所示:
myApp.directive('datepick', function() {
return {
restrict: 'E',
scope: {
ngModel: '='
},
template: '<div ng-if="true"><input type="text" ng-model="ngModel.bar"/></div>'
};
});
所以我使用bar
属性将属性ng-model
传递给它。直到现在一切都按预期工作。模型与渲染形式的变化同步。
下一步我想引入验证来验证当前指令的基础模型上的属性bar
以及MyCtrl3中的一些其他对象 - model
。我为此创建了属性指令foo3
:
myApp.directive('foo3', function() {
return {
restrict: 'A',
require: "ngModel",
link: function(scope, element, attrs, controller) {
scope.$watch(attrs.foo3, function(newValue, oldValue) {
// New Value of comparison field
console.log("New valued for comparison model: " + JSON.stringify(newValue));
// Current value of undelying movelValue
console.log("Current value for undelying model" + JSON.stringify(controller.$modelValue));
controller.$validate();
}, true);
var validateMoreThanDate = function(modelValue, viewValue) {
let viewValueObject = modelValue;
var comparisonModel = scope.$eval(attr.moreThanDateObject);
if ((!viewValueObject && !viewValueObject.bar) ||
(!comparisonModel && !comparisonModel.bar)) {
// It's valid because we have nothing to compare against
return true;
}
// It's valid if model is lower than the model we're comparing against
return viewValueObject.bar > comparisonModel.bar;
};
controller.$validators['moreThanDateObject'] = validateMoreThanDate;
}
};
});
正如您所看到的,我将模型作为参数传递给指令foo3
。监视器跟踪每个更改,但模型更改时不会触发验证器。
问题:如何在我的案例中验证这些字段? (这里有jsFiddle来检查实时代码:https://jsfiddle.net/ichyr/b1jqfkj1/)
N.B。我知道当对象中的模型和此对象的属性发生更改时,不会触发$ parsers和$ formatters管道:
如果新值是一个对象(而不是字符串或数字),我们 应该在将对象传递给$ setViewValue之前复制该对象。 这是因为ngModel不会对对象进行深度监视 只寻找身份的变化。如果您只更改属性 对象然后ngModel将不会意识到该对象具有 已更改,不会调用$ parsers和$ validators管道。
所以也许$ validators也没有触发,但controller.$validate()
的添加对$ watch表达没有帮助。
答案 0 :(得分:0)
我使用 $ watch ers成功完成此任务,而无需执行任何$ parsers,$ formatters或$ validators。如果属性发生变化,前两个肯定不能使用复杂模型。最后一个似乎也不起作用。
我已经通过datepick
和ng-model
+ foo3
指令在foo3
指令中引用了两种型号的两款手表,并创建了小型验证功能。所以myApp.directive('foo3', function() {
return {
restrict: 'A',
require: "ngModel",
link: function(scope, element, attrs, controller) {
scope.$watch(attrs.foo3, function(newValue, oldValue) {
var isValid = validateMoreThanDate(controller.$modelValue, newValue);
controller.$setValidity('moreThanDateObject', isValid);
}, true);
scope.$watch(attrs.ngModel, function(newValue, oldValue) {
var isValid = validateMoreThanDate(newValue, scope.$eval(attrs.foo3));
controller.$setValidity('moreThanDateObject', isValid);
}, true);
var validateMoreThanDate = function(underlyingModel, comparisonModel) {
if ((!underlyingModel && !underlyingModel.bar) ||
(!comparisonModel && !comparisonModel.bar)) {
// It's valid because we have nothing to compare against
return true;
}
// It's valid if model is lower than the model we're comparing against
return underlyingModel.bar > comparisonModel.bar;
};
}
};
});
验证属性指令现在看起来像这样:
// Directive to format the data in the text inputs
myApp.directive('numberInputParser', function() {
return {
restrict: 'A',
require: "ngModel",
link: function(scope, element, attrs, controller) {
debugger;
controller.$parsers.unshift(function(data) {
return parseInt(data);
});
controller.$formatters.unshift(function(data) {
debugger;
return data;
});
}
};
});
此外,我还创建了一个小的装饰指令,用于格式化和解析输入inself中的值(测试类型导致字符串值):
datepick
并且number-input-parser
指令的代码被尊重地更改了(添加了myApp.directive('datepick', function() {
return {
restrict: 'E',
scope: {
ngModel: '='
},
template: '<div ng-if="true"><input type="text" ng-model="ngModel.bar" number-input-parser/></div>'
};
});
指令):
{{1}}
可以在此处看到生成的代码:https://jsfiddle.net/ichyr/f1qeey37/
答案 1 :(得分:0)
N.B。我的同事提出了更好的方法。
可以改进此解决方案。我们可以在datepick
指令中使用自定义getter / setter函数的人工对象来省略$watchers
的使用,如下所示:
myApp.directive('datepick', function() {
return {
restrict: 'E',
scope: {
ngModel: '='
},
template: '<div ng-if="model.open"><input type="text" ng-model="model.value"/></div>',
link: function(scope) {
scope.model = {
get value() {
return scope.ngModel;
},
set value(newValue) {
scope.ngModel = parseInt(newValue);
},
open: true
};
}
};
});
当我们在那里传递对象时,这克服了ng-if
范围中变量的阴影,而不是原始的。
这种方式带来了以下好处:
datepick
指令$watch
表达式,因为我们正在破坏本机JS功能(从而提高性能)datepicker
的参数(模型),以便能够利用angular.js $ parsers , $ formatters 或 $ validators (如果模型是对象,它们不起作用/检测对象属性的变化)您可以在此处找到最终的小提琴:https://jsfiddle.net/ichyr/suncp2gf/