I have a reactive form for entering sales that has multiple identical lines (item#, description, quantity, retail, and extended retail). It is using a FormArray if that makes any difference on the answer. If I add (change)="onChangeItem($event) to the itemNumber field, the function is fired as expected. However, I can't figure out which itemNumber field was changed (i.e. which line). The only solution I have come up with is to append the index to the id of each field so the ids will be like itemNumber1, itemNumber2, etc. but that seems like an odd way to do it. Is there something in the event that tell me which item was changed or is there another way to determine this? My goal is to not process every line every time one line changes.
Add a comment
|
1 Answer
You can use this approach:
Here is the typescript file code.
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray, Validators } from '@angular/forms';
@Component({
selector: 'app-sales-form',
templateUrl: './sales-form.component.html',
styleUrls: ['./sales-form.component.css']
})
export class SalesFormComponent implements OnInit {
form: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.form = this.fb.group({
items: this.fb.array([this.createItem()])
});
// Subscribe to valueChanges on the FormArray itself
this.items.valueChanges.subscribe((values: any[]) => {
console.log('FormArray value changed:', values);
// Process only the modified item
});
}
get items(): FormArray {
return this.form.get('items') as FormArray;
}
// Create a new FormGroup for each item
createItem(): FormGroup {
return this.fb.group({
itemNumber: ['', Validators.required],
description: ['', Validators.required],
quantity: [1, Validators.required],
retail: [0, Validators.required],
extendedRetail: [0, Validators.required]
});
}
// Add a new item to the array
addItem(): void {
this.items.push(this.createItem());
}
// Remove an item from the array
removeItem(index: number): void {
this.items.removeAt(index);
}
// Handle individual field changes
onChangeItem(event: any, index: number, field: string): void {
console.log(`Item at index ${index} changed in field ${field}:`, event);
// Handle item change here (you can optimize based on the field)
}
// Handle form submission
onSubmit(): void {
console.log(this.form.value);
}
}
Here is the html file code.
<form [formGroup]="form" (ngSubmit)="onSubmit()">
<div formArrayName="items">
<div *ngFor="let item of items.controls; let i = index" [formGroupName]="i">
<!-- Item Number -->
<label for="itemNumber{{i}}">Item #</label>
<input
id="itemNumber{{i}}"
formControlName="itemNumber"
(change)="onChangeItem($event, i, 'itemNumber')"
/>
<!-- Description -->
<label for="description{{i}}">Description</label>
<input
id="description{{i}}"
formControlName="description"
(change)="onChangeItem($event, i, 'description')"
/>
<!-- Quantity -->
<label for="quantity{{i}}">Quantity</label>
<input
id="quantity{{i}}"
formControlName="quantity"
(change)="onChangeItem($event, i, 'quantity')"
/>
<!-- Retail Price -->
<label for="retail{{i}}">Retail</label>
<input
id="retail{{i}}"
formControlName="retail"
(change)="onChangeItem($event, i, 'retail')"
/>
<!-- Extended Retail -->
<label for="extendedRetail{{i}}">Extended Retail</label>
<input
id="extendedRetail{{i}}"
formControlName="extendedRetail"
(change)="onChangeItem($event, i, 'extendedRetail')"
/>
<button type="button" (click)="removeItem(i)">Remove Item</button>
</div>
</div>
<button type="button" (click)="addItem()">Add Item</button>
<button type="submit" [disabled]="form.invalid">Submit</button>
</form>
4 Comments
Smith5646
I never thought about adding additional parms. Great idea However, why are you subscribing to valueChanges in ngOnInit? This is not needed when using (change), correct? I just want to make sure that I am not overlooking something.
Ravi Gaud
You're absolutely right! The
valueChanges subscription gives you the entire object of the FormArray whenever any field changes, while onChangeItem will only give you the value of the specific input that was modified. If you're only interested in tracking individual field changes, you can safely remove the valueChanges subscription. However, if you ever need the entire object for processing, it could still be useful. 😊Smith5646
Thanks for the answer and a special thanks for including very detailed code. I wanted to post my code with my question but it was so messed up, I wasn't sure that I knew what I was doing with it. I ended up deleting most of it and started over using your sample.
Ravi Gaud
You're very welcome! I'm glad the code was helpful to you.