如何使用表单生成器从 API 获取数据到 Angular Mat editable table?
how to get data from API to Angular Mat editable table using Form builder?
这是我尝试过的,并且可以很好地处理硬编码数据源。但是从 api 获取数据时抛出错误,如“错误类型错误:无法读取未定义的 属性 'foreach'”和“错误错误:无法找到具有路径的控件:'users -> 0'”。
ngOnInit() {
this.empService.getEmployees().subscribe((res: any[]) => {
this.dataSource = new MatTableDataSource(res);
});
this.tableForm = this.formBuilder.group({
users: this.formBuilder.array([]),
});
console.log(this.dataSource);
this.setUsersForm();
this.tableForm.get("users").valueChanges.subscribe((users) => {
console.log("users", users);
});
}
private setUsersForm() {
const userCtrl = this.tableForm.get("users") as FormArray;
console.log(this.dataSource);
this.dataSource.foreach((user) => {
console.log(user);
userCtrl.push(this.setUsersFormArray(user));
});
}
private setUsersFormArray(user) {
return this.formBuilder.group({
employee_name: [user.employee_name],
location: [user.location],
});
}
<form [formGroup]="tableForm">
<mat-table formArrayName="users" [dataSource]="dataSource">
<ng-container matColumnDef="EmployeeName">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell
*matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex"
>
<input type="text" size="2" formControlName="employee_name" />
</mat-cell>
</ng-container>
<ng-container matColumnDef="Location">
<mat-header-cell *matHeaderCellDef>Location </mat-header-cell>
<mat-cell
*matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex"
>
<input type="text" size="7" formControlName="location" />
</mat-cell>
</ng-container>
<!-- Header and Row Declarations -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</form>
您不需要有两个单独的数据:dataSource 和 FormArray 并使用 valuesChange。您可以使用 FormArray.controls 作为 mat-table.
的数据源
一如既往地使用 From 数组,创建 FormArray
的 getter
get formArray()
{
return this.tableForm.get('users') as FormArray
}
在 ngOnInit 中,在订阅中创建 FormGroup
ngOnInit() {
this.empService.getEmployees().subscribe((res: any[]) => {
this.tableForm = this.formBuilder.group({
users: this.formBuilder.array(res.map(x => this.setUsersFormArray(x)))
});
});
}
了解我们如何使用映射将响应 (res) - objects- 的数组转换为 FormGroups 数组。
.html 喜欢你的代码 - 否则数据源 -
<form [formGroup]="tableForm">
<mat-table formArrayName="users" [dataSource]="formArray.controls">
<ng-container matColumnDef="EmployeeName">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="2" formControlName="employee_name">
</mat-cell>
</ng-container>
<ng-container matColumnDef="Location">
<mat-header-cell *matHeaderCellDef>Location </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="7" formControlName="location">
</mat-cell>
</ng-container>
<!-- Header and Row Declarations -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</form>
真的,如果你只是想管理一个Form数组,你不需要创建一个FormGroup,你可以直接使用formArray
tableFormArray:FormArray
ngOnInit() {
this.empService.getEmployees().subscribe((res: any[]) => {
this.tableFormArray=this.formBuilder.array(res.map(x => this.setUsersFormArray(x)))
});
}
<form [formGroup]="tableFormArray">
<mat-table [dataSource]="tableFormArray.controls">
<ng-container matColumnDef="EmployeeName">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="2" formControlName="employee_name">
</mat-cell>
</ng-container>
<ng-container matColumnDef="Location">
<mat-header-cell *matHeaderCellDef>Location </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="7" formControlName="location">
</mat-cell>
</ng-container>
<!-- Header and Row Declarations -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</form>
您可以在 this stackblitz 中看到这两个方法(在 stackblitz 中,我 return 在自己的组件中观察到一个,将 this.getEmployes 更改为您的 this.empService.getEmployes)
已更新 如果我们想在 header 中使用 select 过滤列,我们可以采用这种方法(我不确定它是否是最好的方法,也许使用过滤器或过滤选项)。这个想法是,在这种情况下,数据源是一个数字数组,其索引为 formArray 中的“selected”元素。为此
//after create the form array:
this.rowsSelects=this.formArray.controls.map((x,index)=>index)
/* a function to "filter"
see that we map each formGroup of the formArray in an object with `{index:#,select:true or false}`
after filter to get only "select", and map to get an array of numbers
*/
selectName(name: string) {
if (name) {
this.rowsSelects = this.formArray.controls
.map((x, index) => ({
index: index,
select: x.value.employee_name == name
}))
.filter(x => x.select)
.map(x => x.index);
} else {
this.rowsSelects = this.formArray.controls.map((x, index) => index);
}
}
作为数据源,我们将使用 rowsSelects
并管理我们使用类似
的 formArray
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroup]="formArray.at(row)">
<input type="text" size="2" formControlName="employee_name">
</mat-cell>
这是我尝试过的,并且可以很好地处理硬编码数据源。但是从 api 获取数据时抛出错误,如“错误类型错误:无法读取未定义的 属性 'foreach'”和“错误错误:无法找到具有路径的控件:'users -> 0'”。
ngOnInit() {
this.empService.getEmployees().subscribe((res: any[]) => {
this.dataSource = new MatTableDataSource(res);
});
this.tableForm = this.formBuilder.group({
users: this.formBuilder.array([]),
});
console.log(this.dataSource);
this.setUsersForm();
this.tableForm.get("users").valueChanges.subscribe((users) => {
console.log("users", users);
});
}
private setUsersForm() {
const userCtrl = this.tableForm.get("users") as FormArray;
console.log(this.dataSource);
this.dataSource.foreach((user) => {
console.log(user);
userCtrl.push(this.setUsersFormArray(user));
});
}
private setUsersFormArray(user) {
return this.formBuilder.group({
employee_name: [user.employee_name],
location: [user.location],
});
}
<form [formGroup]="tableForm">
<mat-table formArrayName="users" [dataSource]="dataSource">
<ng-container matColumnDef="EmployeeName">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell
*matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex"
>
<input type="text" size="2" formControlName="employee_name" />
</mat-cell>
</ng-container>
<ng-container matColumnDef="Location">
<mat-header-cell *matHeaderCellDef>Location </mat-header-cell>
<mat-cell
*matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex"
>
<input type="text" size="7" formControlName="location" />
</mat-cell>
</ng-container>
<!-- Header and Row Declarations -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</form>
您不需要有两个单独的数据:dataSource 和 FormArray 并使用 valuesChange。您可以使用 FormArray.controls 作为 mat-table.
的数据源一如既往地使用 From 数组,创建 FormArray
的 getterget formArray()
{
return this.tableForm.get('users') as FormArray
}
在 ngOnInit 中,在订阅中创建 FormGroup
ngOnInit() {
this.empService.getEmployees().subscribe((res: any[]) => {
this.tableForm = this.formBuilder.group({
users: this.formBuilder.array(res.map(x => this.setUsersFormArray(x)))
});
});
}
了解我们如何使用映射将响应 (res) - objects- 的数组转换为 FormGroups 数组。
.html 喜欢你的代码 - 否则数据源 -
<form [formGroup]="tableForm">
<mat-table formArrayName="users" [dataSource]="formArray.controls">
<ng-container matColumnDef="EmployeeName">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="2" formControlName="employee_name">
</mat-cell>
</ng-container>
<ng-container matColumnDef="Location">
<mat-header-cell *matHeaderCellDef>Location </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="7" formControlName="location">
</mat-cell>
</ng-container>
<!-- Header and Row Declarations -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</form>
真的,如果你只是想管理一个Form数组,你不需要创建一个FormGroup,你可以直接使用formArray
tableFormArray:FormArray
ngOnInit() {
this.empService.getEmployees().subscribe((res: any[]) => {
this.tableFormArray=this.formBuilder.array(res.map(x => this.setUsersFormArray(x)))
});
}
<form [formGroup]="tableFormArray">
<mat-table [dataSource]="tableFormArray.controls">
<ng-container matColumnDef="EmployeeName">
<mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="2" formControlName="employee_name">
</mat-cell>
</ng-container>
<ng-container matColumnDef="Location">
<mat-header-cell *matHeaderCellDef>Location </mat-header-cell>
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroupName]="rowIndex">
<input type="text" size="7" formControlName="location">
</mat-cell>
</ng-container>
<!-- Header and Row Declarations -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
</form>
您可以在 this stackblitz 中看到这两个方法(在 stackblitz 中,我 return 在自己的组件中观察到一个,将 this.getEmployes 更改为您的 this.empService.getEmployes)
已更新 如果我们想在 header 中使用 select 过滤列,我们可以采用这种方法(我不确定它是否是最好的方法,也许使用过滤器或过滤选项)。这个想法是,在这种情况下,数据源是一个数字数组,其索引为 formArray 中的“selected”元素。为此
//after create the form array:
this.rowsSelects=this.formArray.controls.map((x,index)=>index)
/* a function to "filter"
see that we map each formGroup of the formArray in an object with `{index:#,select:true or false}`
after filter to get only "select", and map to get an array of numbers
*/
selectName(name: string) {
if (name) {
this.rowsSelects = this.formArray.controls
.map((x, index) => ({
index: index,
select: x.value.employee_name == name
}))
.filter(x => x.select)
.map(x => x.index);
} else {
this.rowsSelects = this.formArray.controls.map((x, index) => index);
}
}
作为数据源,我们将使用 rowsSelects
并管理我们使用类似
<mat-cell *matCellDef="let row let rowIndex = index"
[formGroup]="formArray.at(row)">
<input type="text" size="2" formControlName="employee_name">
</mat-cell>