我对 FormArray 做错了什么?

What am I doing wrong with 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>

再见

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

this.addCountries 必须 return 一个 FormGroup 数组。如果你使用 map,你会在 元素中得到一个新数组,它是原始数组的一个转换。所以

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>

确实在官方文档中解释的不好,但是你可以看看,例如this Netanel Basal's entry

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

  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 控件更改)时都会检查它