Home > front end >  Disable a button based on multiple empty formControlNames in an Angular Reactive Form
Disable a button based on multiple empty formControlNames in an Angular Reactive Form

Time:11-16

StackBlitz example

I have a reactive form with a dynamic form array. There is a button to add new objects to the form. However, I only want this button to be "enabled" when the current object in the array has been populated/or is already populated.

 <div *ngIf="form">
  <form [formGroup]="form">
    <div formArrayName="justificationItems">
      <div *ngFor="let orgs of form.controls['justificationItems']?.controls;  let i = index"
        [formGroupName]="i">
        <input formControlName="name" placeholder="Item name">
        <input formControlName="description" placeholder="Item description">
        <input formControlName="code" placeholder="Item price">
        </div>
        <button [disabled]="!form.controls['justificationItems']?.controls.description" type="button" (click)="addItem()">Add Item</button>
      </div>
  </form>
</div>

I need to add the attribute of disabled based on 3 fields to look to see if they are empty. I tried this with one field to start with:

[disabled]="!form.controls['justificationItems']?.controls.description"

I thought the above would look at the description fields and see if it has value.

Any alternative methods welcome. I think the issue is that it needs to look at an array item.

StackBlitz example

CodePudding user response:

Your forked Stackblitz here.

Check the values in the last array item and disable the button based on the value.

Place the button inside looped div for getting the access of i (index)

<button
      *ngIf="i == form.value.justificationItems.length - 1"
      [disabled]="
        !form.value.justificationItems[i].name ||
        !form.value.justificationItems[i].description ||
        !form.value.justificationItems[i].code
      "
      type="button"
      (click)="addItem()"
    >  Add Item
        </button>

CodePudding user response:

I would use an observable, mainly because I like to handle all logic in template, also this is more reusable in my opinion instead of typing out all controls in template. What if you want to do a more complicated check for disabling, or what if your form control names change? This is easier to handle in my opinion. But yeah, it's an opinion, but thought to throw this out there :)

So listen to the valuechanges of the formarray, at this point, only address the last item in the array and check that all properties of this object has values:

  this.isDisabled$ = this.form.get('justificationItems').valueChanges.pipe(
    map(value => value[value.length-1]),
    map(val => Object.keys(val).some(x => val[x] === "")),
  )

Then in template use async pipe that unsubscribes for you :)

<button [disabled]="isDisabled$ | async" type="button" (click)="addItem()">Add Item</button>

I used Object.keys above as Stackblitz didn't like me using Object.values, so Object.values is also a valid approach!

DEMO

  • Related