首页 > 解决方案 > 我在 FormArray 上做错了什么?

问题描述

在我的表单中,我将包含以下元素:

  1. 输入(复选框)
  2. 代码(跨度)
  3. 名称(跨度)

这些值来自服务器,这就是为什么它是动态添加的。

但是,我的算法面临以下问题:

core.js: 6228 ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

只有这个错误没有意义,因为控制台正确地显示了值并且这个家伙是一个数组:

在此处输入图像描述

主要部件

@Component({
    selector: 'zx-create-country-form',
    templateUrl: './create-country-form.component.html',
    styleUrls: ['./create-country-form.component.scss'],
})
export class CreateCountryFormComponent implements OnInit {
    createCountryForm!: FormGroup;
    dataTemp = [
        {
            code: 'BR',
            name: {
                pt_BR: 'Brasil',
            },
        },
        {
            code: 'TST',
            name: {
                pt_BR: 'tst3',
            },
        },
    ];

    constructor(protected readonly componentService: ComponentService, protected readonly formBuilder: FormBuilder) {
        this.createCountryForm = formBuilder.group({
            countries: formBuilder.array(this.addCountries()),
        });
    }

    ngOnInit(): void {}

    addCountries(): FormGroup[] {
        const formsGroups: FormGroup[] = [];

        this.dataTemp.map(country => {
            formsGroups.push(
                this.formBuilder.group({
                    radio: this.formBuilder.control([{ value: false, disabled: true }], [Validators.requiredTrue]),
                    code: this.formBuilder.control(country.code, [Validators.required, Validators.minLength(1), Validators.maxLength(2)]),
                    name: this.formBuilder.control(country.name.pt_BR),
                })
            );
        });

        return formsGroups;
    }
}

子组件

<zx-form [fmGroup]="fmGroup">
    <div [formArrayName]="fmArrayName" *ngFor="let country of fmGroup.controls.countries; let i = index">
        <div [formGroupName]="i">
            <input formControlName="radio" placeholder="Item name" />
            <input formControlName="code" placeholder="Item name" />
            <input formControlName="name" placeholder="Item name" />
            eqqe
        </div>
    </div>
</zx-form>

标签: angularangular-formsangular-formbuilder

解决方案


再见

countries: formBuilder.array(this.addCountries()),

this.addCountries 必须返回一个 FormGroups 数组。如果你使用map,你会在witch element中得到一个新数组,它是原始数组的变换。所以

return this.dataTemp.map(country => 
                this.formBuilder.group({
                    radio: this.formBuilder.control([{ value: false, disabled: true }], [Validators.requiredTrue]),
                    code: this.formBuilder.control(country.code, [Validators.required, Validators.minLength(1), Validators.maxLength(2)]),
                    name: this.formBuilder.control(country.name.pt_BR),
                })
        );

使用 forEach,您可以循环遍历数组并为每个元素制作“一些东西”,就像您尝试的那样

    const formsGroups: FormGroup[] = [];

    this.dataTemp.forEach(country => {
        formsGroups.push(
            this.formBuilder.group({
                radio: this.formBuilder.control([{ value: false, disabled: true }], [Validators.requiredTrue]),
                code: this.formBuilder.control(country.code, [Validators.required, Validators.minLength(1), Validators.maxLength(2)]),
                name: this.formBuilder.control(country.name.pt_BR),
            })
        );
    });

还有一点需要注意的是如何在.html中进行迭代,需要遍历表单Array的控件,为此,创建一个数组的getter

get myArrayForm()
{
     return this.fmGroup.get('fmArrayName') as FormArray
}

并遍历 myArrayForm.controls,但取出 formArray 名称,并看到它没有被 [] 包围

<div formArrayName="fmArrayName">
   <div *ngFor="let country of myArrayForm.controls; let i = index">
        <div [formGroupName]="i">
            <input formControlName="radio" placeholder="Item name" />
            <input formControlName="code" placeholder="Item name" />
            <input formControlName="name" placeholder="Item name" />
            eqqe
        </div>
    </div>
</div>

确实在官方文档中解释得不好,但你可以看到,例如这个 Netanel Basal 的条目

如果数组的至少一个元素为真,则更新为验证器,我们需要为自己的数组创建自定义验证,您可以在自己的组件中创建验证器

  atLeastOne()
  {
    return (formArray:FormArray)=>{
      return formArray.value && formArray.value.filter(x=>x.radio).length<=0?
            {error:"At least one"}:null
    }
  }

并且在创建表单时使用

createCountryForm = this.formBuilder.group({
    countries: this.formBuilder.array(this.addCountries(), this.atLeastOne())
  });

注意:当我们在 FormArray 上创建自定义验证器时,我们需要考虑到每次 formArray(或任何此 FormGroups 或 Forms 控件更改)时都会检查它


推荐阅读