I am doing edit page, so i am using patchValue for my form to set default value. in json it stores right data, but mat-selects default value isn't setting. what am i doing wrong?
i tried setting it with "[value]="item.name"" it works, but i need whole value for sending API request not only name.
my stackblitz
.html
<mat-select #multiSelect formControlName="carPartCategory" [value]="filterForm.value.carPartCategory"
(selectionChange)="onChange($event); getCarPartsSubCategory($event)">
<mat-option>
<ngx-mat-select-search [formControl]="carPartsMultiFilterCtrl" [placeholderLabel]="'search...'"
[noEntriesFoundLabel]="'not found'">
</ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let item of filteredcarParts | async" [value]="item">{{item.name}}
</mat-option>
</mat-select>
<mat-select #multiSelect formControlName="carPartSubCategory" [value]="filterForm.value.carPartSubCategory">
<mat-option>
<ngx-mat-select-search [formControl]="carPartsSubMultiFilterCtrl"
[placeholderLabel]="'search...'" [noEntriesFoundLabel]="'not found'">>
</ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let item of filteredcarPartsSub | async; let i = index;" [value]="item">
{{item.name}}
</mat-option>
</mat-select>
.ts
patchValues(name, carPartSubCategoryId, quantity, comment) {
return this.fb.group({
carPartCategory: [name],
carPartSubCategory: [carPartSubCategoryId],
quantity: [quantity],
comment: [comment],
});
}
const control = <FormArray>this.filterForm.get('categories');
this.chosenCarPartCategories.carPartCategories.forEach((x) => {
control.push(
this.patchValues(x.name, x.carPartSubCategoryId, x.quantity, x.comment)
);
});
CodePudding user response:
There are a few bugs in your code preventing it from working.
Here is a working stackblitz: https://stackblitz.com/edit/angular-ivy-2zdvpu
The main problems are described bellow:
- You must use the
compareWith
function on themat-select-input
in order to change its value usingpatchValue
, as described here Angular patchValue of a mat-select component
HTML:
<mat-select
[compareWith]="compareFnSubcategories"
#multiSelect
formControlName="carPartSubCategory"
[value]="filterForm.value.carPartSubCategory"
>
Typescript:
compareFnSubcategories(c1: { carPartSubCategoryId: string },
c2: { carPartSubCategoryId: string }): boolean {
return c1.carPartSubCategoryId === c2.carPartSubCategoryId;
}
- You are calling
patchValue
only once and after the component is loaded. What you should be doing instead is invokingpatchValue
whenever there is a change in the category select, in order to update the child controls:
Typescript:
//This is the function invoked when the category select changes.
//It is here where you should invoke patchValue
getCarPartsSubCategory(event: any, index: number) {
const control = <FormArray>this.filterForm.get('categories');
const selectedCategory = this.chosenCarPartCategories.carPartCategories
.find(cp => cp.carPartCategoryId === event.value.carPartCategoryId);
control.controls[index].patchValue({
carPartSubCategory: selectedCategory,
quantity: selectedCategory.quantity,
comment: selectedCategory.comment,
});
}
- As you have a formArray of categories, the patchValue must be called only in the controls of the array index where the on change event happened. So you have to use the array index as a param to the function handling on change events:
See bellow how the index i
of the formArray of categories is supplied as argument to the getCarPartsSubCategory(...)
function.
HTML:
<div
*ngFor="let obj of formArrCat.controls; let i = index; let l = last"
[formGroupName]="i"
>
<mat-select
...
(selectionChange)="
onChange($event); getCarPartsSubCategory($event, i)
"
>
...
</mat-select>
</div>