Angular 带有嵌套表单数组的反应式表单
Angular Reactive Forms with nested Form Arrays
我是 Angular 2 的新手,我认为最好的学习方法是阅读官方 Angular 指南。
我阅读了 Reactive Forms 指南
https://angular.io/guide/reactive-forms
演示 link:https://stackblitz.com/angular/jammvmbrpxle
虽然内容总体上还不错,但我仍然在思考如何实现更复杂的表单。在给定的示例中,每个 Hero 都有可能拥有多个地址。地址本身是一个平面对象。
如果 Addresses 有额外的信息,例如位于该地址的房间的颜色和类型,会怎样。
export class Address {
street = '';
city = '';
state = '';
zip = '';
rooms = Room[];
}
export class Room {
type = '';
}
以便表单模型看起来像这样...
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})]),
})]),
power: '',
sidekick: ''
});
}
编辑 - 与 ngOnChanges 一起使用的最终代码
英雄-detail.component.ts
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})
])
})
]),
power: '',
sidekick: ''
});
}
ngOnChanges() {
this.heroForm.reset({
name: this.hero.name,
});
this.setAddresses(this.hero.addresses);
}
setAddresses(addresses: Address[]) {
let control = this.fb.array([]);
addresses.forEach(x => {
control.push(this.fb.group({
street: x.street,
city: x.city,
state: x.state,
zip: x.zip,
rooms: this.setRooms(x) }))
})
this.heroForm.setControl('secretLairs', control);
}
setRooms(x) {
let arr = new FormArray([])
x.rooms.forEach(y => {
arr.push(this.fb.group({
type: y.type
}))
})
return arr;
}
hero-detail.component.html(嵌套表单数组部分)
<div formArrayName="secretLairs" class="well well-lg">
<div *ngFor="let address of heroForm.get('secretLairs').controls; let i=index" [formGroupName]="i" >
<!-- The repeated address template -->
<h4>Address #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
<div formArrayName="rooms" class="well well-lg">
<div *ngFor="let room of address.get('rooms').controls; let j=index" [formGroupName]="j" >
<h4>Room #{{j + 1}}</h4>
<div class="form-group">
<label class="center-block">Type:
<input class="form-control" formControlName="type">
</label>
</div>
</div>
</div>
</div>
<button (click)="addLair()" type="button">Add a Secret Lair</button>
</div>
编辑:2021 随着类型检查变得更加严格(很好!),我们需要做一些改变。使用 getter 无法输入嵌套的格式数组。您可以改用函数,但我不喜欢这个想法,因为它会在每次更改检测时调用。相反,我正在解决类型检查并改用 ['controls']
。如果你确实想为嵌套数组(项目)使用更强的类型,请使用一个函数,但请记住它在每次更改检测时都会被调用......所以这里是更新的代码:
嵌套格式数组并没有太大的不同。基本上你只需复制你拥有的代码......使用嵌套数组:)所以这是一个示例:
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = this.fb.group({
// you can also set initial formgroup inside if you like
companies: this.fb.array([])
})
}
// getter for easier access
get companiesFormArr(): FormArray {
return this.myForm.get('companies') as FormArray;
}
addNewCompany() {
this.companiesFormArr.push(
this.fb.group({
company: [''],
projects: this.fb.array([])
})
);
}
deleteCompany(index: number) {
this.companiesFormArr.removeAt(index);
}
所以这是最外层表单数组的添加和删除,因此向嵌套表单数组添加和删除表单组只是重复代码。从模板中我们将当前表单组传递到您要添加的数组(在本例中)一个新的 project/delete 项目。
addNewProject(control) {
control.push(
this.fb.group({
projectName: ['']
}))
}
deleteProject(control, index) {
control.removeAt(index)
}
和模板以同样的方式迭代你的外部数组,然后在里面迭代你的内部数组:
<form [formGroup]="myForm">
<div formArrayName="companies">
<div *ngFor="let comp of companiesFormArr.controls; let i=index">
<h3>COMPANY {{i+1}}: </h3>
<div [formGroupName]="i">
<input formControlName="company" />
<button (click)="deleteCompany(i)">
Delete Company
</button>
<div formArrayName="projects">
<!-- Here I has worked around the typechecking,
if you want stronger typechecking, call a function.
Remember: function called on each change detection! -->
<div *ngFor="let project of comp.get('projects')['controls']; let j=index">
<h4>PROJECT {{j+1}}</h4>
<div [formGroupName]="j">
<input formControlName="projectName" />
<button (click)="deleteProject(comp.get('projects'), j)">
Delete Project
</button>
</div>
</div>
<button (click)="addNewProject(comp.get('projects'))">
Add new Project
</button>
</div>
</div>
</div>
</div>
DEMO
编辑:
要在获得数据后为表单设置值,您可以调用以下方法来迭代数据并为表单设置值。在这种情况下 data
看起来像:
data = {
companies: [
{
company: "example comany",
projects: [
{
projectName: "example project",
}
]
}
]
}
我们调用 setCompanies
为我们的表单设置值:
setCompanies() {
this.data.companies.forEach(x => {
this.companiesFormArr.push(this.fb.group({
company: x.company,
projects: this.setProjects(x) }))
})
}
setProjects(x) {
let arr = new FormArray([])
x.projects.forEach(y => {
arr.push(this.fb.group({
projectName: y.projectName
}))
})
return arr;
}
这是我做的
我使用了 angularflexlayout 和 angular material,你可以使用任何库,只是想向你展示功能
<form [formGroup]="editForm" novalidate fxLayout="column"
autocomplete="off">
<div fxLayout="row wrap" fxLayoutGap="2em">
<mat-form-field [fxFlex]="30">
<mat-label>Name</mat-label>
<input matInput formControlName="name" width="800px"/>
</mat-form-field>
</div>
<div fxLayout="column" fxLayoutGap="3em">
<div fxLayout="row wrap" fxFlex="40" fxLayoutGap="2em">
<div formArrayName="phones" fxFlex="50" fxLayoutGap="8px" *ngFor="let phone of Phones.controls;let i= index">
<mat-form-field fxFlex="100" [formGroupName]="i">
<mat-label>Phone</mat-label>
<input matInput formControlName="phone"/>
</mat-form-field>
</div>
<button type="button" mat-stroked-button color="primary" (click)="addPhone()">add</button>
</div>
<div fxLayout="row wrap" fxFlex="40" fxLayoutGap="2em">
<div formArrayName="emails" fxFlex="50" fxLayoutGap="8px" *ngFor="let email of Emails.controls;let i= index">
<mat-form-field fxFlex="100" [formGroupName]="i">
<mat-label>Email</mat-label>
<input matInput formControlName="email"/>
</mat-form-field>
</div>
<button type="button" mat-stroked-button color="primary" (click)="addEmail()">add</button>
</div>
</div>
<div class="mr-2" fxLayoutAlign="end" mat-dialog-actions>
<button type="button" (click)="cancelDialog()" mat-button
mat-dialog-close>Cancel
</button>
<button type="button" (click)="onSubmit()"
mat-raised-button
color="primary">
Submit
</button>
</div>
</form>
然后 angular 控制器
editForm: FormGroup;
phones: FormArray;
emails: FormArray;
createForm() {
this.editForm = this.fb.group({
name: [''],
phones: this.fb.array([this.createPhone()]),
emails: this.fb.array([this.createEmail()]),
});
}
get Phones() {
return this.editForm.get('phones') as FormArray;
}
get Emails() {
return this.editForm.get('emails') as FormArray;
}
createPhone() {
return this.fb.group(({
phone: '',
}));
}
createEmail() {
return this.fb.group(({
email: ''
}));
}
addPhone(): void {
this.phones = this.editListingForm.get('phones') as FormArray;
this.phones.push(this.createPhone());
}
addEmail(): void {
this.emails = this.editListingForm.get('emails') as FormArray;
this.emails.push(this.createEmail());
}
<tr formArrayName="entries"
*ngFor="let field of entriesGroup.get('entries').controls; let ind1 = index;">
<td [formGroupName]="ind1">
<input type="text" disabled formControlName="date1" name="date1"
class="form-control">
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="startingLocation" name="startingLocation"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="endingLocation" name="endingLocation"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="odometerReadStartingPoint"
name="odometerReadStartingPoint" class="form-control"
[ngModel]="ind1!=0?entriesGroup.get('entries').controls[ind1-1].get('odometerReadingDetails').get('odometerReadEndingPoint').value:field.get('odometerReadingDetails').get('odometerReadStartingPoint').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="odometerReadEndingPoint"
name="odometerReadEndingPoint" class="form-control"
[ngModel]="ind1<entriesGroup.get('entries').controls.length-1?entriesGroup.get('entries').controls[ind1+1].get('odometerReadingDetails').get('odometerReadStartingPoint').value:field.get('odometerReadingDetails').get('odometerReadEndingPoint').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" disabled formControlName="odometerReadForOfficial"
name="odometerReadForOfficial" class="form-control"
[ngModel]="field.get('odometerReadingDetails').get('totalKilometersCovered').value-field.get('odometerReadingDetails').get('odometerReadForPersonal').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="odometerReadForPersonal"
name="odometerReadForPersonal" class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" disabled formControlName="totalKilometersCovered"
name="totalKilometersCovered" class="form-control"
[ngModel]="field.get('odometerReadingDetails').get('odometerReadEndingPoint').value!=0?field.get('odometerReadingDetails').get('odometerReadEndingPoint').value-field.get('odometerReadingDetails').get('odometerReadStartingPoint').value:0">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<textarea rows="2" cols="20" type="text" formControlName="particularTravel"
name="particularTravel" class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="fuelFilled" name="fuelFilled"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="costPerLiter" name="costPerLiter"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" disabled formControlName="costOfTheFuel" name="costOfTheFuel"
class="form-control"
[ngModel]="field.get('fuelDetails').get('costPerLiter').value * field.get('fuelDetails').get('fuelFilled').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" disabled formControlName="fuelConsumption"
name="fuelConsumption" class="form-control"
[ngModel]="field.get('fuelDetails').get('costOfTheFuel').value!=0?(ind1!=0?(entriesGroup.get('entries').controls[ind1-1].get('fuelDetails').get('fuelConsumption').value + field.get('fuelDetails').get('costOfTheFuel').value):field.get('fuelDetails').get('costOfTheFuel').value):0">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="NoNeed">
<div formGroupName="fuelDetails">
<input type="text" formControlName="requestId" name="requestId"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponCode" name="couponCode"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideDate">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponDate" name="couponDate"
placeholder="date1,date2,..." class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponNumber" name="couponNumber"
placeholder="coupon1,coupon2,..." class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideDate">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponsAmount" name="couponsAmount"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="totalKmsCoveredBeforeRepair"
name="totalKmsCoveredBeforeRepair" class="form-control" readonly
[ngModel]="field.get('odometerReadingDetails').get('totalKilometersCovered').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="sparesCost" name="sparesCost"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="labourCost" name="labourCost"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="vehicleRepaireCost"
name="vehicleRepaireCost" class="form-control"
[ngModel]="field.get('vehicleRepairDetails').get('sparesCost').value*1 + field.get('vehicleRepairDetails').get('labourCost').value*1">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<textarea rows="2" cols="20" type="text" formControlName="particularsOfRepairs"
name="particularsOfRepairs" class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<select formControlName="workshopId" class="form-control"
(click)="workshopDetails1($event,ind1)">
<option *ngFor="let i of workshopdata"
[selected]="i.workShopId==field.get('vehicleRepairDetails').get('workshopId').value">
{{i.workShopId}}</option>
<option value="others">OTHERS</option>
</select>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<textarea rows="2" cols="50" type="text" formControlName="workshopAddress"
name="workshopAddress" class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="workshopContactNumber"
name="workshopContactNumber" class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<textarea rows="2" cols="50" type="text"
formControlName="workshopAccountDetails" name="workshopAccountDetails"
class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="requestId" name="requestId"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<select formControlName="categoryType" class="form-control"
(click)="onCatType1($event,ind1)">
<option>Choose</option>
<option *ngFor="let i of driverChargesLimit"
[selected]="i.categoryType==field.get('driverChargesDetails').get('categoryType').value">
{{i.categoryType}}</option>
</select>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<input type="text" formControlName="amount" name="amount" class="form-control"
disabled>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<input type="time" formControlName="startingTime" name="startingTime"
class="form-control" (change)="onStartTime1($event,ind1)">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<input type="time" formControlName="endingTime"
(change)="onEndTime1($event,ind1)" name="endingTime" class="form-control">
</div>
</td>
</tr>
</tbody>
</div>
</table>
我是 Angular 2 的新手,我认为最好的学习方法是阅读官方 Angular 指南。
我阅读了 Reactive Forms 指南 https://angular.io/guide/reactive-forms
演示 link:https://stackblitz.com/angular/jammvmbrpxle
虽然内容总体上还不错,但我仍然在思考如何实现更复杂的表单。在给定的示例中,每个 Hero 都有可能拥有多个地址。地址本身是一个平面对象。
如果 Addresses 有额外的信息,例如位于该地址的房间的颜色和类型,会怎样。
export class Address {
street = '';
city = '';
state = '';
zip = '';
rooms = Room[];
}
export class Room {
type = '';
}
以便表单模型看起来像这样...
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})]),
})]),
power: '',
sidekick: ''
});
}
编辑 - 与 ngOnChanges 一起使用的最终代码
英雄-detail.component.ts
createForm() {
this.heroForm = this.fb.group({
name: '',
secretLairs: this.fb.array([
this.fb.group({
street: '',
city: '',
state: '',
zip: '',
rooms: this.fb.array([
this.fb.group({
type: ''
})
])
})
]),
power: '',
sidekick: ''
});
}
ngOnChanges() {
this.heroForm.reset({
name: this.hero.name,
});
this.setAddresses(this.hero.addresses);
}
setAddresses(addresses: Address[]) {
let control = this.fb.array([]);
addresses.forEach(x => {
control.push(this.fb.group({
street: x.street,
city: x.city,
state: x.state,
zip: x.zip,
rooms: this.setRooms(x) }))
})
this.heroForm.setControl('secretLairs', control);
}
setRooms(x) {
let arr = new FormArray([])
x.rooms.forEach(y => {
arr.push(this.fb.group({
type: y.type
}))
})
return arr;
}
hero-detail.component.html(嵌套表单数组部分)
<div formArrayName="secretLairs" class="well well-lg">
<div *ngFor="let address of heroForm.get('secretLairs').controls; let i=index" [formGroupName]="i" >
<!-- The repeated address template -->
<h4>Address #{{i + 1}}</h4>
<div style="margin-left: 1em;">
<div class="form-group">
<label class="center-block">Street:
<input class="form-control" formControlName="street">
</label>
</div>
<div class="form-group">
<label class="center-block">City:
<input class="form-control" formControlName="city">
</label>
</div>
<div class="form-group">
<label class="center-block">State:
<select class="form-control" formControlName="state">
<option *ngFor="let state of states" [value]="state">{{state}}</option>
</select>
</label>
</div>
<div class="form-group">
<label class="center-block">Zip Code:
<input class="form-control" formControlName="zip">
</label>
</div>
</div>
<br>
<!-- End of the repeated address template -->
<div formArrayName="rooms" class="well well-lg">
<div *ngFor="let room of address.get('rooms').controls; let j=index" [formGroupName]="j" >
<h4>Room #{{j + 1}}</h4>
<div class="form-group">
<label class="center-block">Type:
<input class="form-control" formControlName="type">
</label>
</div>
</div>
</div>
</div>
<button (click)="addLair()" type="button">Add a Secret Lair</button>
</div>
编辑:2021 随着类型检查变得更加严格(很好!),我们需要做一些改变。使用 getter 无法输入嵌套的格式数组。您可以改用函数,但我不喜欢这个想法,因为它会在每次更改检测时调用。相反,我正在解决类型检查并改用 ['controls']
。如果你确实想为嵌套数组(项目)使用更强的类型,请使用一个函数,但请记住它在每次更改检测时都会被调用......所以这里是更新的代码:
嵌套格式数组并没有太大的不同。基本上你只需复制你拥有的代码......使用嵌套数组:)所以这是一个示例:
myForm: FormGroup;
constructor(private fb: FormBuilder) {
this.myForm = this.fb.group({
// you can also set initial formgroup inside if you like
companies: this.fb.array([])
})
}
// getter for easier access
get companiesFormArr(): FormArray {
return this.myForm.get('companies') as FormArray;
}
addNewCompany() {
this.companiesFormArr.push(
this.fb.group({
company: [''],
projects: this.fb.array([])
})
);
}
deleteCompany(index: number) {
this.companiesFormArr.removeAt(index);
}
所以这是最外层表单数组的添加和删除,因此向嵌套表单数组添加和删除表单组只是重复代码。从模板中我们将当前表单组传递到您要添加的数组(在本例中)一个新的 project/delete 项目。
addNewProject(control) {
control.push(
this.fb.group({
projectName: ['']
}))
}
deleteProject(control, index) {
control.removeAt(index)
}
和模板以同样的方式迭代你的外部数组,然后在里面迭代你的内部数组:
<form [formGroup]="myForm">
<div formArrayName="companies">
<div *ngFor="let comp of companiesFormArr.controls; let i=index">
<h3>COMPANY {{i+1}}: </h3>
<div [formGroupName]="i">
<input formControlName="company" />
<button (click)="deleteCompany(i)">
Delete Company
</button>
<div formArrayName="projects">
<!-- Here I has worked around the typechecking,
if you want stronger typechecking, call a function.
Remember: function called on each change detection! -->
<div *ngFor="let project of comp.get('projects')['controls']; let j=index">
<h4>PROJECT {{j+1}}</h4>
<div [formGroupName]="j">
<input formControlName="projectName" />
<button (click)="deleteProject(comp.get('projects'), j)">
Delete Project
</button>
</div>
</div>
<button (click)="addNewProject(comp.get('projects'))">
Add new Project
</button>
</div>
</div>
</div>
</div>
DEMO
编辑:
要在获得数据后为表单设置值,您可以调用以下方法来迭代数据并为表单设置值。在这种情况下 data
看起来像:
data = {
companies: [
{
company: "example comany",
projects: [
{
projectName: "example project",
}
]
}
]
}
我们调用 setCompanies
为我们的表单设置值:
setCompanies() {
this.data.companies.forEach(x => {
this.companiesFormArr.push(this.fb.group({
company: x.company,
projects: this.setProjects(x) }))
})
}
setProjects(x) {
let arr = new FormArray([])
x.projects.forEach(y => {
arr.push(this.fb.group({
projectName: y.projectName
}))
})
return arr;
}
这是我做的 我使用了 angularflexlayout 和 angular material,你可以使用任何库,只是想向你展示功能
<form [formGroup]="editForm" novalidate fxLayout="column"
autocomplete="off">
<div fxLayout="row wrap" fxLayoutGap="2em">
<mat-form-field [fxFlex]="30">
<mat-label>Name</mat-label>
<input matInput formControlName="name" width="800px"/>
</mat-form-field>
</div>
<div fxLayout="column" fxLayoutGap="3em">
<div fxLayout="row wrap" fxFlex="40" fxLayoutGap="2em">
<div formArrayName="phones" fxFlex="50" fxLayoutGap="8px" *ngFor="let phone of Phones.controls;let i= index">
<mat-form-field fxFlex="100" [formGroupName]="i">
<mat-label>Phone</mat-label>
<input matInput formControlName="phone"/>
</mat-form-field>
</div>
<button type="button" mat-stroked-button color="primary" (click)="addPhone()">add</button>
</div>
<div fxLayout="row wrap" fxFlex="40" fxLayoutGap="2em">
<div formArrayName="emails" fxFlex="50" fxLayoutGap="8px" *ngFor="let email of Emails.controls;let i= index">
<mat-form-field fxFlex="100" [formGroupName]="i">
<mat-label>Email</mat-label>
<input matInput formControlName="email"/>
</mat-form-field>
</div>
<button type="button" mat-stroked-button color="primary" (click)="addEmail()">add</button>
</div>
</div>
<div class="mr-2" fxLayoutAlign="end" mat-dialog-actions>
<button type="button" (click)="cancelDialog()" mat-button
mat-dialog-close>Cancel
</button>
<button type="button" (click)="onSubmit()"
mat-raised-button
color="primary">
Submit
</button>
</div>
</form>
然后 angular 控制器
editForm: FormGroup;
phones: FormArray;
emails: FormArray;
createForm() {
this.editForm = this.fb.group({
name: [''],
phones: this.fb.array([this.createPhone()]),
emails: this.fb.array([this.createEmail()]),
});
}
get Phones() {
return this.editForm.get('phones') as FormArray;
}
get Emails() {
return this.editForm.get('emails') as FormArray;
}
createPhone() {
return this.fb.group(({
phone: '',
}));
}
createEmail() {
return this.fb.group(({
email: ''
}));
}
addPhone(): void {
this.phones = this.editListingForm.get('phones') as FormArray;
this.phones.push(this.createPhone());
}
addEmail(): void {
this.emails = this.editListingForm.get('emails') as FormArray;
this.emails.push(this.createEmail());
}
<tr formArrayName="entries"
*ngFor="let field of entriesGroup.get('entries').controls; let ind1 = index;">
<td [formGroupName]="ind1">
<input type="text" disabled formControlName="date1" name="date1"
class="form-control">
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="startingLocation" name="startingLocation"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="endingLocation" name="endingLocation"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="odometerReadStartingPoint"
name="odometerReadStartingPoint" class="form-control"
[ngModel]="ind1!=0?entriesGroup.get('entries').controls[ind1-1].get('odometerReadingDetails').get('odometerReadEndingPoint').value:field.get('odometerReadingDetails').get('odometerReadStartingPoint').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="odometerReadEndingPoint"
name="odometerReadEndingPoint" class="form-control"
[ngModel]="ind1<entriesGroup.get('entries').controls.length-1?entriesGroup.get('entries').controls[ind1+1].get('odometerReadingDetails').get('odometerReadStartingPoint').value:field.get('odometerReadingDetails').get('odometerReadEndingPoint').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" disabled formControlName="odometerReadForOfficial"
name="odometerReadForOfficial" class="form-control"
[ngModel]="field.get('odometerReadingDetails').get('totalKilometersCovered').value-field.get('odometerReadingDetails').get('odometerReadForPersonal').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" formControlName="odometerReadForPersonal"
name="odometerReadForPersonal" class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<input type="text" disabled formControlName="totalKilometersCovered"
name="totalKilometersCovered" class="form-control"
[ngModel]="field.get('odometerReadingDetails').get('odometerReadEndingPoint').value!=0?field.get('odometerReadingDetails').get('odometerReadEndingPoint').value-field.get('odometerReadingDetails').get('odometerReadStartingPoint').value:0">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideHeaders">
<div formGroupName="odometerReadingDetails">
<textarea rows="2" cols="20" type="text" formControlName="particularTravel"
name="particularTravel" class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="fuelFilled" name="fuelFilled"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="costPerLiter" name="costPerLiter"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" disabled formControlName="costOfTheFuel" name="costOfTheFuel"
class="form-control"
[ngModel]="field.get('fuelDetails').get('costPerLiter').value * field.get('fuelDetails').get('fuelFilled').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" disabled formControlName="fuelConsumption"
name="fuelConsumption" class="form-control"
[ngModel]="field.get('fuelDetails').get('costOfTheFuel').value!=0?(ind1!=0?(entriesGroup.get('entries').controls[ind1-1].get('fuelDetails').get('fuelConsumption').value + field.get('fuelDetails').get('costOfTheFuel').value):field.get('fuelDetails').get('costOfTheFuel').value):0">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="NoNeed">
<div formGroupName="fuelDetails">
<input type="text" formControlName="requestId" name="requestId"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponCode" name="couponCode"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideDate">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponDate" name="couponDate"
placeholder="date1,date2,..." class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="fuelHide">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponNumber" name="couponNumber"
placeholder="coupon1,coupon2,..." class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="hideDate">
<div formGroupName="fuelDetails">
<input type="text" formControlName="couponsAmount" name="couponsAmount"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="totalKmsCoveredBeforeRepair"
name="totalKmsCoveredBeforeRepair" class="form-control" readonly
[ngModel]="field.get('odometerReadingDetails').get('totalKilometersCovered').value">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="sparesCost" name="sparesCost"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="labourCost" name="labourCost"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="vehicleRepaireCost"
name="vehicleRepaireCost" class="form-control"
[ngModel]="field.get('vehicleRepairDetails').get('sparesCost').value*1 + field.get('vehicleRepairDetails').get('labourCost').value*1">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<textarea rows="2" cols="20" type="text" formControlName="particularsOfRepairs"
name="particularsOfRepairs" class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<select formControlName="workshopId" class="form-control"
(click)="workshopDetails1($event,ind1)">
<option *ngFor="let i of workshopdata"
[selected]="i.workShopId==field.get('vehicleRepairDetails').get('workshopId').value">
{{i.workShopId}}</option>
<option value="others">OTHERS</option>
</select>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<textarea rows="2" cols="50" type="text" formControlName="workshopAddress"
name="workshopAddress" class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="workshopContactNumber"
name="workshopContactNumber" class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="workShop">
<div formGroupName="vehicleRepairDetails">
<textarea rows="2" cols="50" type="text"
formControlName="workshopAccountDetails" name="workshopAccountDetails"
class="form-control">
</textarea>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="repaireHide">
<div formGroupName="vehicleRepairDetails">
<input type="text" formControlName="requestId" name="requestId"
class="form-control">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<select formControlName="categoryType" class="form-control"
(click)="onCatType1($event,ind1)">
<option>Choose</option>
<option *ngFor="let i of driverChargesLimit"
[selected]="i.categoryType==field.get('driverChargesDetails').get('categoryType').value">
{{i.categoryType}}</option>
</select>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<input type="text" formControlName="amount" name="amount" class="form-control"
disabled>
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<input type="time" formControlName="startingTime" name="startingTime"
class="form-control" (change)="onStartTime1($event,ind1)">
</div>
</td>
<td [formGroupName]="ind1" *ngIf="driverHide">
<div formGroupName="driverChargesDetails">
<input type="time" formControlName="endingTime"
(change)="onEndTime1($event,ind1)" name="endingTime" class="form-control">
</div>
</td>
</tr>
</tbody>
</div>
</table>