【问题标题】:Dynamic Forms FormArray angular 2动态表单 FormArray 角度 2
【发布时间】:2017-09-28 05:24:49
【问题描述】:

我关注了 Todd Motto 文章中关于 angular 2 (https://toddmotto.com/angular-dynamic-components-forms) 的动态形式的文章。

每件事都完美无缺。

但我有一个项目,一个有趣的项目,我尝试将格式化数组传递给配置,这是数据:

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: {…}}

【问题讨论】:

  • But I don't why I can't access to the controls with form.controls.travel.controls 你想在哪里做这个?
  • @yurzui 在 Html 中:&lt;ng-container dynamicField [config]="field" [group]="form.controls[array].controls[i]"&gt;&lt;/ng-container&gt;。或者,如果我尝试在 console.log() 中访问。
  • stackblitz.com/edit/… 如您所见,它有效。但我没有添加 dynamicField 指令
  • 你能添加完整的错误堆栈吗?
  • @yurzui 关于“travel”数组,我在重写代码时犯了错误。但这不是错误。实际上是的:form.controls[array].controls[i] 也许问题来自指令我已经更新了我的初始帖子。

标签: forms angular


【解决方案1】:

@yurzui 好吧,我的错,我需要在指令中循环配置...天哪,我浪费了这么多时间!感谢您的帮助,它帮助我理解了错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-25
    • 2019-09-21
    • 1970-01-01
    • 2019-01-27
    • 2018-04-18
    • 2017-12-27
    • 1970-01-01
    • 2019-05-13
    相关资源
    最近更新 更多