Angular-FormArray:从二维 Javascript 数组创建 table 表单
Angular-FormArray: Creating a table form from 2-dimensional Javascript array
- 我需要使用 Angular 创建一个 table 表单,它基于一个简单的二维数组数组。
- 数据结构简单,但单元格中的数据相互依赖。单个单元格仅通过索引访问,例如
row:1
、col:0
.
- 需要在单元级别定义自定义验证器。此外,可能还有行和列的验证器。
我尝试了各种方法来定义 FormArray
持有 FormControl
数组。但我不确定如何在 Angular 模板中单独按行和列索引访问相应的 FormControl
。
型号
[
['a', 'b'],
['c', 'd']
]
表格组
form = new FormGroup({
rows: new FormArray([...])
});
预期结果
我试过各种类似的东西:
<form [formGroup]="form"">
<div formArrayName="rows">
<div
*ngFor="let row of rows.controls; let rowIndex = index" [formGroupName]="rowIndex">
<div formArrayName="cols">
<div
*ngFor="let col of form.get('cols').controls; let colIndex = index"
[formGroupName]="colIndex">
<input [formControlName]="colIndex" />
</div>
</div>
</div>
</div>
</form>
Dabbel,如果你有一个 Array of Array,创建一个 FormArrays 的 FormArrays(抱歉开玩笑了)
好吧,想象一下你有
数据=[
['a', 'b'],
['c', 'd']
]
您可以在 ngOnInit 中创建 FormArray 的 formArray,如
//At firs a empty FormArray
this.formArray = new FormArray([]);
//with each element of data
this.data.forEach(x => {
//x is e.g.['a','b']
//we create a emptt FormArray
const obj = new FormArray([]);
//add a FormControl
x.forEach(y => {
obj.push(new FormControl(y));
});
//and push in the formArray
this.formArray.push(obj);
});
或像
这样使用地图缩写
this.formArray=new FormArray(
this.data.map(x=>new FormArray(
x.map(y=>new FormControl(y))))
)
那么,如何在 FormGroup 之外管理 FormArray?如果我们的 FormArray 是 FormGroup 的 FormArray,我们一般使
<!--yes we can use [formGroup] with a FormArray-->
<form [formGroup]="formArray">
<!--iterate over the formArray.controls, that is a formGroup-->
<div *ngFor="let group of formArray.controls;let i=index">
<div [formGroup]="group">
<input formControlName="name">
...
</div>
</div>
</form>
好吧,我们的 formArray 是 FormArray 的 FormArray,但请记住,我们将 [formGroup] 与数组一起使用并迭代 formArray.controls。
<form [formGroup]="formArray">
<div *ngFor="let subarray of formArray.controls;let i=index">
<div [formGroup]="subarray">
<ng-container *ngFor="let control of subarray.controls;let j=index">
<input [formControl]="control">{{control.invalid?"*":""}}
</ng-container>
</div>
</div>
</form>
注意:我使用 <ng-container>
或 <div>
来不创建附加 div。 (我们不能将 *ngFor 放在自己的输入中,因为这样我们就无法访问 control.invalid
好吧,正如您想要创建验证器一样,我们在创建 formGroup 以包含验证器时进行了一些更改,我放了一个 "fool" 示例
this.formArray=new FormArray(
this.data.map(x=>new FormArray(
x.map(y=>new FormControl(y,Validators.required)),
this.rowValidator())),this.arrayValidator()
)
我们的验证器可以像
rowValidator()
{
return (array:FormArray)=> {
const invalid:boolean=array.value.
filter((x,index)=>array.value.indexOf(x)!=index).length>0
return invalid?{error:'must be different'}:null
}
}
arrayValidator()
{
return (array:FormArray)=> {
let arrayJoin="";
array.value.forEach(x=>arrayJoin+=x.join(''))
return arrayJoin=="abcd"?null:{error:'must be a,b,c,d'}
}
}
你可以在stackblitz
中看到
注意:在实际应用中,我们不需要使用那么多验证器。考虑此验证器对应用程序性能的影响
模板表单将使您的生活更轻松。
只需直接绑定到数组本身。
<form>
<div *ngFor="let row of data;let i=index">
<input [name]="prop1_ + i" [(ngModel)]="row.prop1">
<input [name]="prop2_ + i" [(ngModel)]="row.prop2">
</div>
</form>
- 我需要使用 Angular 创建一个 table 表单,它基于一个简单的二维数组数组。
- 数据结构简单,但单元格中的数据相互依赖。单个单元格仅通过索引访问,例如
row:1
、col:0
. - 需要在单元级别定义自定义验证器。此外,可能还有行和列的验证器。
我尝试了各种方法来定义 FormArray
持有 FormControl
数组。但我不确定如何在 Angular 模板中单独按行和列索引访问相应的 FormControl
。
型号
[
['a', 'b'],
['c', 'd']
]
表格组
form = new FormGroup({
rows: new FormArray([...])
});
预期结果
我试过各种类似的东西:
<form [formGroup]="form"">
<div formArrayName="rows">
<div
*ngFor="let row of rows.controls; let rowIndex = index" [formGroupName]="rowIndex">
<div formArrayName="cols">
<div
*ngFor="let col of form.get('cols').controls; let colIndex = index"
[formGroupName]="colIndex">
<input [formControlName]="colIndex" />
</div>
</div>
</div>
</div>
</form>
Dabbel,如果你有一个 Array of Array,创建一个 FormArrays 的 FormArrays(抱歉开玩笑了)
好吧,想象一下你有 数据=[ ['a', 'b'], ['c', 'd'] ]
您可以在 ngOnInit 中创建 FormArray 的 formArray,如
//At firs a empty FormArray
this.formArray = new FormArray([]);
//with each element of data
this.data.forEach(x => {
//x is e.g.['a','b']
//we create a emptt FormArray
const obj = new FormArray([]);
//add a FormControl
x.forEach(y => {
obj.push(new FormControl(y));
});
//and push in the formArray
this.formArray.push(obj);
});
或像
这样使用地图缩写this.formArray=new FormArray(
this.data.map(x=>new FormArray(
x.map(y=>new FormControl(y))))
)
那么,如何在 FormGroup 之外管理 FormArray?如果我们的 FormArray 是 FormGroup 的 FormArray,我们一般使
<!--yes we can use [formGroup] with a FormArray-->
<form [formGroup]="formArray">
<!--iterate over the formArray.controls, that is a formGroup-->
<div *ngFor="let group of formArray.controls;let i=index">
<div [formGroup]="group">
<input formControlName="name">
...
</div>
</div>
</form>
好吧,我们的 formArray 是 FormArray 的 FormArray,但请记住,我们将 [formGroup] 与数组一起使用并迭代 formArray.controls。
<form [formGroup]="formArray">
<div *ngFor="let subarray of formArray.controls;let i=index">
<div [formGroup]="subarray">
<ng-container *ngFor="let control of subarray.controls;let j=index">
<input [formControl]="control">{{control.invalid?"*":""}}
</ng-container>
</div>
</div>
</form>
注意:我使用 <ng-container>
或 <div>
来不创建附加 div。 (我们不能将 *ngFor 放在自己的输入中,因为这样我们就无法访问 control.invalid
好吧,正如您想要创建验证器一样,我们在创建 formGroup 以包含验证器时进行了一些更改,我放了一个 "fool" 示例
this.formArray=new FormArray(
this.data.map(x=>new FormArray(
x.map(y=>new FormControl(y,Validators.required)),
this.rowValidator())),this.arrayValidator()
)
我们的验证器可以像
rowValidator()
{
return (array:FormArray)=> {
const invalid:boolean=array.value.
filter((x,index)=>array.value.indexOf(x)!=index).length>0
return invalid?{error:'must be different'}:null
}
}
arrayValidator()
{
return (array:FormArray)=> {
let arrayJoin="";
array.value.forEach(x=>arrayJoin+=x.join(''))
return arrayJoin=="abcd"?null:{error:'must be a,b,c,d'}
}
}
你可以在stackblitz
中看到注意:在实际应用中,我们不需要使用那么多验证器。考虑此验证器对应用程序性能的影响
模板表单将使您的生活更轻松。
只需直接绑定到数组本身。
<form>
<div *ngFor="let row of data;let i=index">
<input [name]="prop1_ + i" [(ngModel)]="row.prop1">
<input [name]="prop2_ + i" [(ngModel)]="row.prop2">
</div>
</form>