Consider trying a different approach for your template syntax, specifically when iterating through an array of ingredients:
- Use
track by item
instead of $index
- (optional: define a separate variable
index
and pass it to the onDelete
method instead of using $index
)
Here's a suggested code snippet:
@for (item of ingredientControls; track item; let index = $index;) {
<div formArrayName="ingredients">
<div class="container-with-delete">
<mat-form-field class="example-full-width">
<mat-label>Ingredient</mat-label>
<input
matInput
type="text"
[placeholder]="item.value"
[formControlName]="index"
/>
</mat-form-field>
<button type="button" (click)="onDelete(index, 'ingredients')">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
}
For additional information on this topic, check out this resource:
What is the @for tracking function?
The tracking function created via the track statement is used to make
it easy for the Angular change detection mechanism to know exactly
what items to update in the DOM after the input array changes.
edit:
refactor suggestion:
Create a separate method for constructing forms that accepts an object containing default or server data based on the isEditMode
condition:
- In the else section, move the form creation logic to a new method that constructs the form from the provided input object
public constructForm(recipe:any) {
// consider changing to `this.ingredients`
// Alternatively, you may return form controls and apply them with the spread operator:
// return {ingredients: ...}
// Then,
// this.recipeForm = new FormGroup({
// ...returnedControls,
ingredients = new FormArray<FormControl>([]);
steps = new FormArray([]);
prepTimes = new FormArray([]);
this.recipeForm.patchValue(recipe);
// include loops here
}
Create a default data object
defaultFormData = {
ingredients: ['e.g. 2 spoons of sugar powder',...],
steps: ['e.g. 2 spoons of sugar powder',...]
// etc.
};
- Based on the value of
isEditMode
, provide either the default object or retrieve data from the server:
// If not in edit mode, use the default object
if (!this.isEditMode) {
this.constructForm(this.defaultFormData);
} else {
// Fetch data from the server
this._recipeService.fetchRecipe(this.recipeId).subscribe((recipe) => {
this.constructForm(recipe);
}