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.