我对 FormArray 做错了什么?
What am I doing wrong with FormArray?
在我的表单中,我将包含以下元素:
- 输入(复选框)
- 代码(跨度)
- 名称(跨度)
这些值来自服务器,这也是动态添加的原因。
但是,我的算法遇到了以下问题:
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 控件更改)时都会检查它
在我的表单中,我将包含以下元素:
- 输入(复选框)
- 代码(跨度)
- 名称(跨度)
这些值来自服务器,这也是动态添加的原因。
但是,我的算法遇到了以下问题:
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 控件更改)时都会检查它