Issue
I am working on a form in Angular 14.
The form has a main section, containing the user's essential data, and a secondary section, where every user can add additional data (an array of residences that I display in a table), before submitting the form.
This additional data is optional, the fields are not required.
In form.component.ts
I have:
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators, FormArray } from '@angular/forms';
@Component({
selector: 'my-app',
templateUrl: './form.component.html',
styleUrls: ['./form.component.css'],
})
export class FormComponent {
public form: FormGroup = new FormGroup({
first_name: new FormControl('', Validators.required),
last_name: new FormControl('', Validators.required),
email: new FormControl('', [Validators.required, Validators.email]),
phone: new FormControl('', Validators.required),
residences: new FormArray([
new FormGroup({
city: new FormControl(''),
address: new FormControl(''),
}),
]),
});
get residencesArray(): FormArray {
return this.form.get('residences') as FormArray;
}
constructor() {}
ngOnInit(): void {}
public sendFormData() {
console.log(this.form.value);
}
addResidence() {
this.residencesArray.push(
new FormGroup({
city: new FormControl(''),
address: new FormControl(''),
})
);
console.log('Residences');
console.log(this.residencesArray.value);
}
}
In the form.component.html
file I have:
<form [formGroup]="form" class="my-form">
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">Fast name:</mat-label>
<input class="mat-input" matInput formControlName="first_name" />
</mat-form-field>
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">Last name:</mat-label>
<input class="mat-input" matInput formControlName="last_name" />
</mat-form-field>
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">Email:</mat-label>
<input class="mat-input" matInput formControlName="email" />
</mat-form-field>
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">Phone:</mat-label>
<input class="mat-input" matInput formControlName="phone" />
</mat-form-field>
<table *ngIf="this.residencesArray.value.length > 1" class="table">
<thead>
<tr class="table-headers">
<th>City</th>
<th>Address</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="
let residence of this.residencesArray.value.slice(0, -1);
let i = index
"
>
<td>{{ residence.city }}</td>
<td>{{ residence.address }}</td>
</tr>
</tbody>
</table>
<div class="residences-header">
<h4>Residences</h4>
<button
(click)="addResidence()"
mat-raised-button
color="primary"
[disabled]="!form.valid"
>
Add residence
</button>
</div>
<div
class="residence"
formArrayName="residences"
*ngFor="let residence of residencesArray.controls; let i = index"
>
<div [formGroupName]="i">
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">City:</mat-label>
<input class="mat-input" matInput formControlName="city" />
</mat-form-field>
<mat-form-field appearance="outline" floatLabel="always">
<mat-label class="mat-label">Address:</mat-label>
<input class="mat-input" matInput formControlName="address" />
</mat-form-field>
</div>
</div>
<div class="center">
<button
(click)="sendFormData()"
mat-raised-button
color="primary"
[disabled]="!form.valid"
>
Submit
</button>
</div>
</form>
See this Stackblitz for more details.
The problem
The problem with the above is that the array this.residencesArray.value
will always have the last object "invalid": with empty strings for values.
Questions
- Is there a reliable way to get rid of this last object before submitting the form?
- How can I keep the Add residence button disabled as long as the last 2 form fields are empty (but the form is valid)?
Solution
Something like this could work:
public sendFormData() {
for (
let index = this.form.value.residences.length - 1;
index >= 0;
--index
) {
const {city, address} = this.form.value.residences[index];
if (!city && !address) {
this.residencesArray.removeAt(index);
}
}
console.log(this.form.value);
}
The idea is to loop through residences (backward) and remove any index where "city" and "address" is not filled. The criteria can be further tweaked.
Working Stackblitz
Answered By - robert
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.