As the title says, I have a reactive form that has multiple <mat-select>
contained within. On initial form load, the initial option is not displayed even though form.value
shows it is.
Pertinent component.ts:
export class DesJobInfoEditComponent implements OnInit {
...
currentJobData: IJob;
jobTypes: IJobType[];
...
constructor(private fb: FormBuilder) {
...
// Construct forms
this.createForm();
this.initializeForm();
}
createForm() {
this.editJobInfoForm = this.fb.group({
...
JobType: '', // mat-select
...
});
}
initializeForm() {
this.rebuildForm();
}
rebuildForm() {
this.editJobInfoForm.reset({
...
JobType: this.jobTypes[this.currentJobData.JobType].DisplayDesc,
...
});
}
}
Pertinent html:
<mat-form-field fxFlex>
<mat-label>Job Type</mat-label>
<mat-select formControlName="JobType" placeholder="Job Type">
<mat-option *ngFor="let jobType of jobTypes" value="jobType.value">
{{ jobType.DisplayDesc }}
</mat-option>
</mat-select>
</mat-form-field>
When the form loads, the selects do not display the initially selected option, however, they are set properly, apparently:
Form value { ... "JobType": "0 - Standard", ... }
All that displays on the form is the placeholder.
This seems like it should not be this difficult.
What am I doing wrong?
EDIT:
this.jobTypes
is loaded when the module is loaded, and it is a BehaviorSubject that lives in my data service. I subscribe to it in the constructor of this component thusly:
this.data.jobTypes.subscribe(jobTypes => { this.jobTypes = jobTypes });
Angalural Material compareWith: (o1: any, o2: any) => boolean from (API reference for Angular Material select)
component.ts
export class ParentOneComponent implements OnInit {
materialFormSample: FormGroup;
constructor() { }
ngOnInit() {
this.configureMaterialFormSample();
}
name: string = 'Emilius Patrin Mfuruki';
toppingList: string[] = ['Extra cheese', 'Mushroom', 'Onion', 'Pepperoni', 'Sausage', 'Tomato'];
selectedToppingList = ['Extra cheese', 'Tomato', 'Onion'];
compareWithFunc = (a: any, b: any) => a == b;
configureMaterialFormSample() {
this.materialFormSample = new FormGroup({
name: new FormControl(this.name),
toppings: new FormControl(this.selectedToppingList)
})
}
onSubmitForm() {
if (this.materialFormSample.valid) {
console.log('submitting Form Content Valid', this.materialFormSample.value);
}
}
}
component.html
<form [formGroup]="materialFormSample" (ngSubmit)="onSubmitForm()" autocomplete="off">
<mat-form-field class="w-100">
<input matInput placeholder="Name" formControlName="name">
</mat-form-field>
<mat-form-field class="w-100">
<mat-label>Toppings</mat-label>
<mat-select formControlName="toppings" multiple [compareWith]="compareWithFunc">
<mat-option *ngFor="let topping of toppingList" [value]="topping">{{topping}}</mat-option>
</mat-select>
</mat-form-field>
<div class="clearfix">
<button type="submit" mat-raised-button color="primary" class="float-right">Submit Form</button>
</div>
</form>
A few things
[formControlName]
must be used in conjunction with [formGroup]
. If you don't want to use [formControlName]
+ [formGroup]
, you can use [formControl]
instead.
In angular, there is a difference between specifying an attribute as value
and [value]
. When an attribute is enclosed in brackets []
, it is interpreted as javascript / angular template script (same as {{}}
, I think). When it is not enclosed in brackets, it is interpreted as a string (i.e. value="jobType.value"
=== [value]="'jobType.value'"
and [value]="jobType.value"
=== value="{{jobType.value}}"
(actually I think there are subtle differences between [value]="jobType.value"
and value="{{jobType.value}}"
, but w/e)). So when you write <mat-option *ngFor="let jobType of jobTypes" value="jobType.value">
, the value of every mat-option
is "jobType.value"
which, I imagine, isn't want you want. So you need to change the code to <mat-option *ngFor="let jobType of jobTypes" [value]="jobType.value">
e.g.
<mat-form-field [formGroup]='editJobInfoForm' fxFlex>
<mat-label>Job Type</mat-label>
<mat-select formControlName="JobType" placeholder="Job Type">
<mat-option *ngFor="let jobType of jobTypes" [value]="jobType.value">
{{ jobType.DisplayDesc }}
</mat-option>
</mat-select>
</mat-form-field>
Somewhat unrelated to your problem, why have both createForm()
and initializeForm()
methods? Why not simply
constructor(private fb: FormBuilder) {
...
// Construct forms
this.createForm();
}
createForm() {
this.editJobInfoForm = this.fb.group({
...
JobType: this.jobTypes[this.currentJobData.JobType].DisplayDesc,
...
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With