Angular 10 个动态嵌套表单输出到 html table
Angular 10 Dynamic Nested Form output to html table
我有一个 Angular 表单,其中包含使用 FormArray 的动态嵌套表单。我从另一个 post 那里得到了嵌套形式的想法。我正在尝试将嵌套表单输出到 html table 和 rowspan。我想我的结构是正确的,但是当我尝试将嵌套表单呈现为 table 时,header 被推到右边,第一列成为整个输出的列。
我这里有一个 stackblitz 条目:
https://stackblitz.com/edit/angular-ivy-4zjniz?file=src/app/app.component.ts
当表单首次呈现时,它显示如下:
First time on component image
然后,当我点击“添加座位 Emp”和“添加技能”时,header 会像这样被推过去。
Added parent and child image
如何让 header 保持在左侧并为 table 正确呈现?提前谢谢你。
这是我的 html 代码:(app.component.html)
<div class="control-section e-rte-custom-tbar-section">
<div >
<form [formGroup]="empForm" (ngSubmit)="onSubmit()">
<div formArrayName="employees">
<table>
<tr>
<th rowspan="{rowSpan}">Emp #</th>
<th rowspan="{rowSpan}">First</th>
<th rowspan="{rowSpan}">Last</th>
<th rowspan="{rowSpan}">Remove Emp Action</th>
<th>Skill #</th>
<th>Skill</th>
<th>Exp</th>
<th>Remove Skill Action</th>
</tr>
<ng-container *ngFor="let employee of employees().controls; let empIndex=index">
<tr [formGroupName]="empIndex">
<td>{{empIndex}}</td>
<td><input type="text" formControlName="firstName" placeholder="first"></td>
<td><input type="text" formControlName="lastName" placeholder="last"></td>
<td><button (click)="removeEmployee(empIndex)">Remove Emp</button></td>
<div formArrayName="skills">
<ng-container *ngFor="let skill of employeeSkills(empIndex).controls; let skillIndex=index">
<div [formGroupName]="skillIndex">
<tr>
<td>{{skillIndex}}</td>
<td><input type="text" formControlName="skill" placeholder="skill"></td>
<td><input type="text" formControlName="exp" placeholder="exp"></td>
<td><button (click)="removeEmployeeSkill(empIndex,skillIndex)">Remove Skill</button></td>
</tr>
</div>
</ng-container>
<tr><button type="button" (click)="addEmployeeSkill(empIndex)">Add Skill</button></tr>
</div>
</tr>
</ng-container>
</table>
</div>
<p>
<button type="button" (click)="addEmployee()">Add Seat Emp</button>
</p>
<p>
<button type="submit">Submit</button>
</p>
</form>
</div>
</div>
这是代码:(app.component.ts)
import { Component, VERSION } from '@angular/core';
import { FormGroup, FormArray, FormBuilder } from '@angular/forms'
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
title = 'Nested FormArray Example Add Form Fields Dynamically';
empForm:FormGroup;
constructor(private fb:FormBuilder) {
this.empForm=this.fb.group({
employees: this.fb.array([]) ,
})
}
employees(): FormArray {
return this.empForm.get("employees") as FormArray
}
newEmployee(): FormGroup {
return this.fb.group({
firstName: '',
lastName: '',
skills:this.fb.array([])
})
}
addEmployee() {
console.log("Adding a employee");
this.employees().push(this.newEmployee());
}
removeEmployee(empIndex:number) {
this.employees().removeAt(empIndex);
}
employeeSkills(empIndex:number) : FormArray {
return this.employees().at(empIndex).get("skills") as FormArray
}
newSkill(): FormGroup {
return this.fb.group({
skill: '',
exp: '',
})
}
addEmployeeSkill(empIndex:number) {
this.employeeSkills(empIndex).push(this.newSkill());
}
removeEmployeeSkill(empIndex:number,skillIndex:number) {
this.employeeSkills(empIndex).removeAt(skillIndex);
}
onSubmit() {
console.log(this.empForm.value);
}
}
export class country {
id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
}
这一行:
<div *ngFor="let employee of employees().controls; let empIndex=index">
混淆了 table 的标记,因为它添加了额外的 div
.
你可以改成这样:
<ng-container *ngFor="let employee of employees().controls; let empIndex=index">
然后多余的div
就不加了。我在你的 Stackblitz 中试过了,现在似乎可以正常工作了。
在 Angular docs 中阅读更多 Angular 的 ngContainer
。
深入结构还有另一个问题来自 table 中嵌套的更多 div
个元素。您可以将它们全部替换为 ngContainer
,它也适用于 formArrayName
和 formGroupName
。但是还有一个 tr
元素内嵌套 tr
元素的问题。嵌套的 divs
和 tr
元素对于 table 都是无效的 HTML。
将所有 div
替换为 ngContainer
并删除嵌套的 tr
元素后,您遇到了另一个问题。
所以现在我认为您可能需要重新考虑一下解决方案。一个快速的想法可能是为技能行添加一个嵌套的 table。现在它看起来像这样:
也许它看起来不像你想要的,但它现在至少是一个有效的 HTML table,也许一些 CSS 可以让它看起来更好,如果你改变员工数据单元格的对齐方式。但我不认为有一个 table 可以在同一个 table 中显示所有员工和他们的技能,我认为你需要使用嵌套的 table,就像我的例如,或为此考虑不同的解决方案。
我分叉了你的 Stackblitz 并添加了嵌套的 table here.
我有一个 Angular 表单,其中包含使用 FormArray 的动态嵌套表单。我从另一个 post 那里得到了嵌套形式的想法。我正在尝试将嵌套表单输出到 html table 和 rowspan。我想我的结构是正确的,但是当我尝试将嵌套表单呈现为 table 时,header 被推到右边,第一列成为整个输出的列。
我这里有一个 stackblitz 条目: https://stackblitz.com/edit/angular-ivy-4zjniz?file=src/app/app.component.ts
当表单首次呈现时,它显示如下: First time on component image
然后,当我点击“添加座位 Emp”和“添加技能”时,header 会像这样被推过去。
Added parent and child image
如何让 header 保持在左侧并为 table 正确呈现?提前谢谢你。
这是我的 html 代码:(app.component.html)
<div class="control-section e-rte-custom-tbar-section">
<div >
<form [formGroup]="empForm" (ngSubmit)="onSubmit()">
<div formArrayName="employees">
<table>
<tr>
<th rowspan="{rowSpan}">Emp #</th>
<th rowspan="{rowSpan}">First</th>
<th rowspan="{rowSpan}">Last</th>
<th rowspan="{rowSpan}">Remove Emp Action</th>
<th>Skill #</th>
<th>Skill</th>
<th>Exp</th>
<th>Remove Skill Action</th>
</tr>
<ng-container *ngFor="let employee of employees().controls; let empIndex=index">
<tr [formGroupName]="empIndex">
<td>{{empIndex}}</td>
<td><input type="text" formControlName="firstName" placeholder="first"></td>
<td><input type="text" formControlName="lastName" placeholder="last"></td>
<td><button (click)="removeEmployee(empIndex)">Remove Emp</button></td>
<div formArrayName="skills">
<ng-container *ngFor="let skill of employeeSkills(empIndex).controls; let skillIndex=index">
<div [formGroupName]="skillIndex">
<tr>
<td>{{skillIndex}}</td>
<td><input type="text" formControlName="skill" placeholder="skill"></td>
<td><input type="text" formControlName="exp" placeholder="exp"></td>
<td><button (click)="removeEmployeeSkill(empIndex,skillIndex)">Remove Skill</button></td>
</tr>
</div>
</ng-container>
<tr><button type="button" (click)="addEmployeeSkill(empIndex)">Add Skill</button></tr>
</div>
</tr>
</ng-container>
</table>
</div>
<p>
<button type="button" (click)="addEmployee()">Add Seat Emp</button>
</p>
<p>
<button type="submit">Submit</button>
</p>
</form>
</div>
</div>
这是代码:(app.component.ts)
import { Component, VERSION } from '@angular/core';
import { FormGroup, FormArray, FormBuilder } from '@angular/forms'
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular ' + VERSION.major;
title = 'Nested FormArray Example Add Form Fields Dynamically';
empForm:FormGroup;
constructor(private fb:FormBuilder) {
this.empForm=this.fb.group({
employees: this.fb.array([]) ,
})
}
employees(): FormArray {
return this.empForm.get("employees") as FormArray
}
newEmployee(): FormGroup {
return this.fb.group({
firstName: '',
lastName: '',
skills:this.fb.array([])
})
}
addEmployee() {
console.log("Adding a employee");
this.employees().push(this.newEmployee());
}
removeEmployee(empIndex:number) {
this.employees().removeAt(empIndex);
}
employeeSkills(empIndex:number) : FormArray {
return this.employees().at(empIndex).get("skills") as FormArray
}
newSkill(): FormGroup {
return this.fb.group({
skill: '',
exp: '',
})
}
addEmployeeSkill(empIndex:number) {
this.employeeSkills(empIndex).push(this.newSkill());
}
removeEmployeeSkill(empIndex:number,skillIndex:number) {
this.employeeSkills(empIndex).removeAt(skillIndex);
}
onSubmit() {
console.log(this.empForm.value);
}
}
export class country {
id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
}
这一行:
<div *ngFor="let employee of employees().controls; let empIndex=index">
混淆了 table 的标记,因为它添加了额外的 div
.
你可以改成这样:
<ng-container *ngFor="let employee of employees().controls; let empIndex=index">
然后多余的div
就不加了。我在你的 Stackblitz 中试过了,现在似乎可以正常工作了。
在 Angular docs 中阅读更多 Angular 的 ngContainer
。
深入结构还有另一个问题来自 table 中嵌套的更多 div
个元素。您可以将它们全部替换为 ngContainer
,它也适用于 formArrayName
和 formGroupName
。但是还有一个 tr
元素内嵌套 tr
元素的问题。嵌套的 divs
和 tr
元素对于 table 都是无效的 HTML。
将所有 div
替换为 ngContainer
并删除嵌套的 tr
元素后,您遇到了另一个问题。
所以现在我认为您可能需要重新考虑一下解决方案。一个快速的想法可能是为技能行添加一个嵌套的 table。现在它看起来像这样:
也许它看起来不像你想要的,但它现在至少是一个有效的 HTML table,也许一些 CSS 可以让它看起来更好,如果你改变员工数据单元格的对齐方式。但我不认为有一个 table 可以在同一个 table 中显示所有员工和他们的技能,我认为你需要使用嵌套的 table,就像我的例如,或为此考虑不同的解决方案。
我分叉了你的 Stackblitz 并添加了嵌套的 table here.