Asked By: Anonymous
I am creating a dynamic form with multiple dropdowns (mat-select). The value for the select is the key. After the user has selected all dropdowns I want the selected values to be shown. However, as the select only holds the key and not the value, I am confused how I show achieve my goal.
Option 1 – Use id as value binding
<mat-form-field appearance="fill" *ngSwitchCase="'dropdown'" class="w-75">
<mat-label>{{question.label}}</mat-label>
<mat-select [formControlName]="question.key">
<mat-option *ngFor="let opt of question.options" [value]="opt.key">
{{opt.value}}
</mat-option>
</mat-select>
<mat-error *ngIf="!isValid">
{{question.label}} is required
</mat-error>
</mat-form-field>
Option 2 – Use object as value binding**
I tried earlier to bind the value of the option to be the object itself (opt), that fixed my issue. But instead I was not able to set a default value. In this case I tested with both [value] and [ngValue] without success, example below:
<mat-form-field appearance="fill" *ngSwitchCase="'dropdown'" class="w-75">
<mat-label>{{question.label}}</mat-label>
<mat-select [formControlName]="question.key">
<mat-option *ngFor="let opt of question.options" [value]="opt">
{{opt.value}}
</mat-option>
</mat-select>
<mat-error *ngIf="!isValid">
{{question.label}} is required
</mat-error>
</mat-form-field>
Generates the dropdown just fine. In the case that I want to set the default value, the value is not being selected but it outputs that it is selected as it should..
let testOption = {key: 17, value: "Country 17"};
this.form.controls.country.setValue(testOption); //Updates not visible in mat-select
console.log(this.form.controls.country.value); //Output shows {key: 17, value: "Country 17"}
Any tips on how to solve any of the two options? I really would like to avoid to write a generic function that the html calls for to get the value. (Like in ts doing Array.filter….)
Thanks!
Solution
Answered By: Anonymous
First, create a compare function for your option objects:
compareOptions(option1: Option, option2: Option) {
return option1.key === option2.key;
}
Then supply this function to mat-select:
<form [formGroup]="form">
<mat-form-field appearance="fill" class="w-75">
<mat-label>Question</mat-label>
<mat-select formControlName="question" [compareWith]="compareOptions">
<mat-option *ngFor="let opt of options" [value]="opt">
{{opt.value}}
</mat-option>
</mat-select>
</mat-form-field>
</form>
Then, set the form value and the new object will be compared by your id ‘key’ instead:
this.form.get('question')?.setValue({key: 3, value: 'Country 3'});
https://stackblitz.com/edit/angular-wqvgfk?file=src%2Fapp%2Fselect-custom-trigger-example.ts
Alternatively, you could find the option in the array using the ID and set the form control value to that. Since it is the same object reference, you will not need a compare function:
this.form.get('question')?.setValue(this.options.find(opt => opt.key === 3));
https://stackblitz.com/edit/angular-wqvgfk-ymkixm?file=src%2Fapp%2Fselect-custom-trigger-example.ts