3

希望这将是一个更通用的 Angular JS 问题,而不是特定于 Angular Formly 的问题。

我一直在遵循此处提供的框架,以在有角度的形式上构建错误摘要。一切正常......但是!

在示例中,他们的模型如下:

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 布局,如此处所述那么您的模型最终会看起来像我的模型:

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,或者这是我应该在指令本身的代码中处理的东西。

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 次!我已经添加了一些基本的转义来尝试解决这个问题,现在至少我有错误,我遇到的下一个问题是在我调用的 HTML 中,ng-repeat="field in vm.fields"这实际上是同一个问题,所以我将如何解决这个问题? 我的一部分是在考虑一些匿名对象,它会保存字段消息以及是否有效,然后在 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>

我仍然对此不是 100% 满意,它完成了工作,但我不确定这是否是“角度”的方式,而且我$scope.$watch在字段对象上使用的事实有点烦人我的开发人员强迫症,但解决方案都是一样的。

如果有人对此有任何改进或改进建议,请告诉我,仍然可以掌握 Angular,但这是一次非常有趣的学习体验!

4

0 回答 0