Navin Hotwani
Navin Hotwani

Reputation: 339

how to watch for valueChanges on a control within a formGroup under a dynamic formArray

i am new to Angular 2/4 and also to web development in general. I have this form that collects the information of variants of products in a purchase form. I have built a formArray of formGroups of variants as shown in below HTML.

<form [formGroup]="this.purchaseInvoiceItemVariantsForm" novalidate>
    <div formArrayName="variants">
        <div *ngFor="let variant of this.purchaseInvoiceItemVariantsForm.controls.variants.controls; let i = index">
            <div [formGroupName]="i">
                <md-input-container>
                    <input mdInput placeholder="Product Code"  formControlName="productBarcode" class="input--small" [readonly]="this.mode == 'view'">
                </md-input-container>
                <md-input-container>
                    <input mdInput placeholder="Color" formControlName="variant1" class="input--small" [readonly]="this.mode == 'view'" required>
                </md-input-container>
                <md-input-container>
                    <input mdInput placeholder="Size" formControlName="variant2" class="input--small" [readonly]="this.mode == 'view'" required>
                </md-input-container>
                <md-input-container>
                    <input mdInput placeholder="MRP" formControlName="mrp" class="input--small" [readonly]="this.mode == 'view'">
                </md-input-container>
                <md-input-container>
                    <input mdInput placeholder="Purchase Price" formControlName="purchasePrice" class="input--small" [readonly]="this.mode == 'view'"
                        required>
                </md-input-container>
                <md-input-container>
                    <input mdInput placeholder="Sell Price" formControlName="sellPrice" class="input--small" [readonly]="this.mode == 'view'"
                        required>
                </md-input-container>
                <md-input-container>
                    <input mdInput placeholder="Quantity" formControlName="variantQuantity" class="input--small" [readonly]="this.mode == 'view'" required>
                </md-input-container>
                <md-input-container>
                    <input mdInput placeholder="Discount" formControlName="variantDiscount" class="input--small" [readonly]="this.mode == 'view'">
                </md-input-container>
                <button md-icon-button (click)="removeVariant(i)" color="warn" *ngIf="purchaseInvoiceItemVariantsForm.controls.variants.length > 1 && this.mode != 'view'"><md-icon>delete</md-icon></button>
            </div>
        </div>

Now once the user have added say 3 variants, i want to be able to listen to the valueChanges of the formControl "productBarcode" so that i can fetch the color and size details from the database.

Any suggestions how this can be achieved ?

thanks in advance!

Regards, Navin

Upvotes: 10

Views: 9390

Answers (3)

shan22
shan22

Reputation: 131

Use valueChanges for each control after adding control dynamically to FormGroup.

const ct = {key: 'myControl'};    
this.myForm.addControl(ct.key, new FormControl('', Validators.required))
this.myForm.controls[ct.key].valueChanges
.subscribe(d => {
    // here ct will be available as closure , so that we can access every form control here and do operation accordingly
    console.log(d, ct.key);
})

Here ct object will be available inside subscribe as a closure.

Upvotes: 0

AVJT82
AVJT82

Reputation: 73377

We could do a version of the valueChanges, which starts listening when the variants-array length is a >= 3. Then we listen to each change in the barcode.

I assume you have a function where you add new controls to your variants array, we could implement it there:

addVariant() {
  // code here for adding control

  // check length   
  if(this.purchaseInvoiceItemVariantsForm.get('variants').length >= 3) {
    // iterate each object in array
    for(let val of this.purchaseInvoiceItemVariantsForm.get('variants').controls) {
      // listen to changes in each barcode, if change, do something!
      val.get('productBarcode').valueChanges.subscribe(data => {
      console.log(val.get('productBarcode').value)
      // do something!
      })
    }
  } 
}

Demo

Upvotes: 5

SrAxi
SrAxi

Reputation: 20015

I would go for ngDoCheck(). It listens constantly for changes, and you can then add some logic. Is helping me a lot.

An example:

ngDoCheck() {
    if (this.arraOfItems.length > 3) {
        // Do stuff
    }
}

And in your class you should implement DoCheck, like this:

export class myClass implements OnInit, DoCheck {}

this way, if you manage to add your items to an array, per say: arraOfItems. Then it will work.

Documentation: https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html#!#docheck

Another approach:

In the logic where you add items to arraOfItems, make a check and add your logic, for example:

addingItemToArray(item) {
    this.arraOfItems.push(item);
    if (this.arraOfItems.length > 3) {
       // do stuff 
    }
}

This example considers that you created an addingItemToArray method that adds the items to the array. Inside its logic you can put a control that checks the length of the array and if you added more than 3 items then does whatever you want it to do.

Upvotes: 1

Related Questions