使用fieldGroups

时间:2015-06-26 10:39:13

标签: javascript angularjs angular-formly

希望这将是一个更通用的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,但这是一个非常有趣的学习经历!

0 个答案:

没有答案