希望这将是一个更通用的Angular JS问题,而不是Angular Formly特有的问题。
我一直在关注提供here的框架,以便在角度形式上构建错误摘要。一切都很好.....但是!
在示例中,他们的模型如下:
vm.fields = [
{
key: 'picky',
type: 'customInput',
templateOptions: {
label: 'Picky field...',
placeholder: 'This is required and has a maxlength of 5 and minlength of 3',
required: true,
maxlength: 5,
minlength: 3
}
},
.....
{
key: 'ip',
type: 'customInput',
validators: {
ipAddress: {
expression: function(viewValue, modelValue) {
var value = modelValue || viewValue;
return /(\d{1,3}\.){3}\d{1,3}/.test(value);
},
message: '$viewValue + " is not a valid IP Address"'
}
},
templateOptions: {
label: 'IP Address',
required: true,
type: 'text',
placeholder: '127.0.0.1',
}
}
];
然后,如果我们查看HTML,我们可以看到这些字段正在传递到错误摘要中:
<formly-error-summary form="vm.form" fields="vm.fields"></formly-error-summary>
对于简单的表单结构,这很好用,但是,如果你想使用Bootstrap布局,如here所述,那么你的模型最终会看到我的作品:
vm.rentalFields = [
{
template: '<div class="row"><div class="col-xs-12"><h3>About You</h3></div></div>'
},
{
className: 'row',
fieldGroup: [
{
className: 'col-xs-6',
type: 'customInput',
key: 'first_name',
templateOptions: {
type: 'text',
label: 'First Name',
placeholder: 'Enter your first name',
required: true
}
},
{
className: 'col-xs-6',
type: 'customInput',
key: 'last_name',
templateOptions: {
type: 'text',
label: 'Last Name',
placeholder: 'Enter your last name',
required: true
},
expressionProperties: {
'templateOptions.disabled': '!model.first_name'
}
}
]
},
{
template: '<div class="row"><div class="col-xs-12"><h3>License and Insurance Details</h3></div></div>',
hideExpression: '!model.email'
}
.....
现在,当我们将vm.rentalFields传递给错误摘要时,而不是访问字段,而是仅验证每个对象。我可以通过做类似的事情来解决这个问题:
<formly-error-summary form="vm.rentalForm" fields="vm.rentalFields[1].fieldGroup"></formly-error-summary>
这当然不理想,因为我会想要验证其他字段组中的字段,以便证明问题虽然现在没问题。我试过传递'vm.rentalFields.fieldGroup'但是我怀疑它没有返回。
那么,有没有办法可以递归传递vm.rentalField对象中的所有fieldGroups,或者这是我应该在Directive本身的代码中处理的东西。
angular.module("formlyApp").directive('formlyErrorSummary', function() {
return {
scope: {},
bindToController: {
form: '=',
fields: '='
},
templateUrl: 'js/Directives/formly-error-summary.html',
controllerAs: 'vm',
controller: function() {
var vm = this;
vm.getErrorAsList = getErrorAsList;
console.log(vm.fields);
function getErrorAsList(field) {
return Object.keys(field.formControl.$error).map(function(error) {
// note, this only works because the customInput type we have defined.
return field.data.getValidationMessage(error);
}).join(', ');
}
}
};
});
修改
好的,所以,在接受了Ken的建议之后,我已经能够修改我的formlyErrorSummary指令,以便它现在至少能够获得模型的错误。这有很多问题,因为$ scope。$ watch正在进行深层次的比较,甚至在第一页加载时,整个事情被解雇了3次!我已经添加了一些基本的逃脱试图对抗这个,现在至少我有错误,我的下一个问题是在我称之为ng-repeat="field in vm.fields"
的HTML中,这实际上是同一个问题,所以如何我会为此工作吗?我的一部分是考虑一些匿名对象,它将保存字段消息以及是否有效,然后在HTML中解析它,但我不确定这种思维方式是否适用于Angular?
controller: function($scope) {
var vm = this;
$scope.$watch('vm.fields', function(){
for(var i = 0; i < vm.fields.length; i++)
if(vm.fields[i].fieldGroup) {
for(var j = 0; j < vm.fields[i].fieldGroup.length; j ++)
if(vm.fields[i].fieldGroup[j].formControl) {
var err = getErrorAsList(vm.fields[i].fieldGroup[j]);
if(err)
vm.getErrorAsList = err;
}
}
}, true);
解决方案 - 可能
经过多次黑客攻击,我认为我终于有了这个工作,现在错误消息显示在内联和顶部的摘要中。
我的最终指令函数现在每次运行时创建一个数组,它将保存所有错误消息,必须在$watch
内刷新,否则当字段有效时,错误消息将持续存在数组所以我们每次都只是重建整个事物.....鉴于我已经在这里使用了一个深层次的手表,我希望任何性能命中都可以忽略不计。
vm.errs = [];
$scope.$watch('vm.fields', function(){
vm.errs = [];
for(var i = 0; i < vm.fields.length; i++)
if(vm.fields[i].fieldGroup) {
for(var j = 0; j < vm.fields[i].fieldGroup.length; j ++)
if(vm.fields[i].fieldGroup[j].formControl) {
var err = getErrorAsList(vm.fields[i].fieldGroup[j]);
if(err)
if(vm.errs.indexOf(err) === -1)
vm.errs.push(err);
}
}
}, true);
然后,在指令模板中,我不得不删除vm.fields
引用,因为这显然不适合这种方法。由于我知道只有在表单被激活时才会显示此摘要,因此我可以删除正在执行的其他检查,最终使用以下HTML结束:
<div class="row">
<div class="col-xs-12">
<div class="formly-error-summary bg-danger" ng-if="vm.form.$invalid">
<div ng-repeat="err in vm.errs" class="color-error">
<i class="glyphicon glyphicon-remove"></i>
<span>
{{err}}
</span>
</div>
</div>
</div>
</div>
我仍然不是百分之百满意,它完成了工作,但我不确定这是否是'Angular'这样做的方式以及我正在使用$scope.$watch
的事实fields对象对我的开发人员OCD来说有点烦人,但解决方案却完全相同。
如果有人对此有任何改进或建议,请告诉我,仍然要掌握Angular,但这是一个非常有趣的学习经历!