1

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

2 Answers 2

1

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>
Sign up to request clarification or add additional context in comments.

2 Comments

any options of not having the button inside the loop?
Yaa, one more stackblitz bellow - stackblitz.com/edit/…
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.