Dynamic Forms FormArray angular 2

时间:2017-09-27 19:57:34

标签: forms angular

我遵循Todd Motto关于动态形式的文章,角度为2(https://toddmotto.com/angular-dynamic-components-forms)。

每件事情都很完美。

但是我有一个项目,为了愉快的项目,我尝试将格式化的数组传递给config,这是数据:

travel = [
    {
        type: 'input',
        label: 'From',
        placeholder: 'From',
        name: 'from', 
    },
    {
        type: 'input',
        label: 'To',
        placeholder: 'To',
        name: 'to'
    }
];

travellers = [
    {
        type: 'input',
        label: 'Name',
        placeholder: 'name',
        name: 'name', 
    }
]

config = {
    travel: [       
        {
            ...this.travel
        },
        {
            ...this.travel
        }
    ],
    travellers: [
        {
            ...this.travellers
        }
    ]
};

这里是动态表单组件的调用:

<dynamic-form [config]="config" (submitted)="formSubmitted($event)"></dynamic-form>

这是动态表单组件:

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormArray, FormControl, FormBuilder } from '@angular/forms';
import * as _ from 'lodash';

@Component({
    selector: 'builder-form',
    templateUrl: './builder-form.component.html',
    styleUrls: ['./builder-form.component.css']
})
export class BuilderFormComponent implements OnInit {

    @Input()
    config: any[] = [];

    @Output()
    submitted: EventEmitter<any> = new EventEmitter<any>();

    form: FormGroup;

    objectKeys = Object.keys;

    constructor (private fb: FormBuilder) { }

    ngOnInit() {
        this.form = this.createGroup();
    }

    createGroup () {

        const group = this.fb.group({});

        let groupArray = Object.keys(this.config);

        let control;

        groupArray.forEach((value, i) => {
            group.addControl(value, this.fb.array([]));
            control = group.controls[value] as FormArray;

            _.map(this.config[value], (val, key) => {
                // object is the travel { from, to } and the traveller { name }
                let object = {}
                _.map(val, (v, k) => {
                    Object.assign(object, {[v.name]: null})
                });
                control.push(this.fb.group(object, this.fb.control(null)));
            });
        });

        return group;
   }
}

我明白了:

FormGroup {
    ...
    controls {
        travel: FormArray {
             ...
             controls: [
                 0: FormGroup {
                      controls: { form: FormControl, to: FormControl }
                 },
                 1: FormGroup {
                      controls: { form: FormControl, to: FormControl }
                 }
             ]
             ...
        },

        travellers: FormArray {
             ...
             controls: [
                 0: FormGroup {
                      controls: { name: FormControl }
                 }
             ]
             ...
        }
    }
    ...
}

这似乎很好。

但我不知道为什么我无法使用form.controls.travel.controlsform.controls['travel'].controls访问控件我总是收到错误:'AbstractControl'类型中不存在属性'控件'

在HTML中:

<form class="dynamic-form" [formGroup]="form" (ngSubmit)="submitted.emit(form.value)">
    <ng-container *ngFor="let array of objectKeys(config)">
        <div [formArrayName]="array">
            <ng-container *ngFor="let field of config[array]; let i = index" [formGroupName]="i">
                <ng-container dynamicField [config]="field" [group]="form.controls[array].controls[i]"></ng-container>
            </ng-container>
        </div>
    </ng-container>

</form>

但这不起作用......

{{ form.value }}返回正确的对象:

{
  "travel": [
    {
      "from": null,
      "to": null
    },
    {
      "from": null,
      "to": null
    }
  ],
  "travellers": [
    {
      "name": null
    }
  ]
}

你是如何使它有效的?

更新

也许错误就在这里:

import { Directive, Input, ComponentFactoryResolver, OnInit, ViewContainerRef } from '@angular/core';
import { FormGroup } from '@angular/forms';

import { FormButtonComponent, FormInputComponent, FormSelectComponent, FormResetComponent, FormDateComponent, FormNumberComponent } from '../components';

const components = {
    button: FormButtonComponent,
    input: FormInputComponent
};

@Directive({
    selector: '[dynamicField]'
})
export class DynamicFieldDirective implements OnInit {
    @Input()
    config;

    @Input()
    group: FormGroup;

    component;

    constructor (
        private resolver: ComponentFactoryResolver,
        private container: ViewContainerRef  
    ) {}

    ngOnInit () {
        const component = components[this.config.type];
        const factory = this.resolver.resolveComponentFactory<any>(component);
        this.component = this.container.createComponent(factory);
        this.component.instance.config = this.config;
        this.component.instance.group = this.group;
    }
}

更新2

BuilderFormComponent.html:12 ERROR Error: No component factory found for undefined. Did you add it to @NgModule.entryComponents?
    at noComponentFactoryError (core.es5.js:3202)
    at CodegenComponentFactoryResolver.webpackJsonp.../../../core/@angular/core.es5.js.CodegenComponentFactoryResolver.resolveComponentFactory (core.es5.js:3267)
    at BuilderFieldDirective.webpackJsonp.../../../../../src/app/builder-form/directives/builder-field.directive.ts.BuilderFieldDirective.ngOnInit (builder-field.directive.ts:35)
    at checkAndUpdateDirectiveInline (core.es5.js:10856)
    at checkAndUpdateNodeInline (core.es5.js:12357)
    at checkAndUpdateNode (core.es5.js:12296)
    at debugCheckAndUpdateNode (core.es5.js:13160)
    at debugCheckDirectivesFn (core.es5.js:13101)
    at Object.eval [as updateDirectives] (BuilderFormComponent.html:13)
    at Object.debugUpdateDirectives [as updateDirectives] (core.es5.js:13086)
View_BuilderFormComponent_2 @ BuilderFormComponent.html:12
webpackJsonp.../../../core/@angular/core.es5.js.DebugContext_.logError @ core.es5.js:13426
webpackJsonp.../../../core/@angular/core.es5.js.ErrorHandler.handleError @ core.es5.js:1080
(anonymous) @ core.es5.js:4819
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:392
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run @ zone.js:142
webpackJsonp.../../../core/@angular/core.es5.js.NgZone.runOutsideAngular @ core.es5.js:3844
webpackJsonp.../../../core/@angular/core.es5.js.ApplicationRef_.tick @ core.es5.js:4819
webpackJsonp.../../../core/@angular/core.es5.js.ApplicationRef_._loadComponent @ core.es5.js:4787
webpackJsonp.../../../core/@angular/core.es5.js.ApplicationRef_.bootstrap @ core.es5.js:4775
(anonymous) @ core.es5.js:4546
webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_._moduleDoBootstrap @ core.es5.js:4546
(anonymous) @ core.es5.js:4508
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:392
onInvoke @ core.es5.js:3890
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke @ zone.js:391
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run @ zone.js:142
(anonymous) @ zone.js:844
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:425
onInvokeTask @ core.es5.js:3881
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:424
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask @ zone.js:192
drainMicroTaskQueue @ zone.js:602
Promise resolved (async)
scheduleMicroTask @ zone.js:585
webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:414
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:236
webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleMicroTask @ zone.js:256
scheduleResolveOrReject @ zone.js:842
ZoneAwarePromise.then @ zone.js:932
webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_._bootstrapModuleWithZone @ core.es5.js:4537
webpackJsonp.../../../core/@angular/core.es5.js.PlatformRef_.bootstrapModule @ core.es5.js:4522
../../../../../src/main.ts @ main.ts:11
__webpack_require__ @ bootstrap 92732b2f740421148d04:54
0 @ main.bundle.js:1187
__webpack_require__ @ bootstrap 92732b2f740421148d04:54
webpackJsonpCallback @ bootstrap 92732b2f740421148d04:25
(anonymous) @ main.bundle.js:1
BuilderFormComponent.html:12 ERROR CONTEXT DebugContext_ {view: {…}, nodeIndex: 1, nodeDef: {…}, elDef: {…}, elView: {…}}

1 个答案:

答案 0 :(得分:0)

@yurzui好吧我的坏,我需要在指令中循环配置... OMG我失去了这么多时间!谢谢你的帮助,这帮助我理解了这个错误。