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