Home > Enterprise >  How can I eliminate items with empty strings as values from this array of objects?
How can I eliminate items with empty strings as values from this array of objects?

Time:02-04

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" >
  <mat-form-field appearance="outline" floatLabel="always">
    <mat-label >Fast name:</mat-label>
    <input  matInput formControlName="first_name" />
  </mat-form-field>

  <mat-form-field appearance="outline" floatLabel="always">
    <mat-label >Last name:</mat-label>
    <input  matInput formControlName="last_name" />
  </mat-form-field>

  <mat-form-field appearance="outline" floatLabel="always">
    <mat-label >Email:</mat-label>
    <input  matInput formControlName="email" />
  </mat-form-field>

  <mat-form-field appearance="outline" floatLabel="always">
    <mat-label >Phone:</mat-label>
    <input  matInput formControlName="phone" />
  </mat-form-field>

  <table *ngIf="this.residencesArray.value.length > 1" >
    <thead>
      <tr >
        <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 >
    <h4>Residences</h4>
    <button
      (click)="addResidence()"
      mat-raised-button
      color="primary"
      [disabled]="!form.valid"
    >
      Add residence
    </button>
  </div>

  <div
    
    formArrayName="residences"
    *ngFor="let residence of residencesArray.controls; let i = index"
  >
    <div [formGroupName]="i">
      <mat-form-field appearance="outline" floatLabel="always">
        <mat-label >City:</mat-label>
        <input  matInput formControlName="city" />
      </mat-form-field>

      <mat-form-field appearance="outline" floatLabel="always">
        <mat-label >Address:</mat-label>
        <input  matInput formControlName="address" />
      </mat-form-field>
    </div>
  </div>

  <div >
    <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

  1. Is there a reliable way to get rid of this last object before submitting the form?
  2. How can I keep the Add residence button disabled as long as the last 2 form fields are empty (but the form is valid)?

CodePudding user response:

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

CodePudding user response:

Another way (but I love the Robert's answer)

  submit(form)
  {
    const values=form.value.residences.filter((x:any)=>x.city || x.address)
    while (this.residences.controls.length>values.length)
      this.residences.removeAt(0)

    this.residences.setValue(values)
  }

NOTE: Really if only want to send the values we can not change the formArray, only send de data we can make something like:

submit(form)
{
   const data={...form.value,
               residences:form.value.residences.filter(
                   (x:any)=>x.city || x.address)
               }
   myService.update(data)
}
  • Related