I have a mat-select form element tied to a FormControl for validation. The goal is to give an error box below the element if the select box isn't filled in (or nothing is selected)
However the form is valid when submitting with no select option is chosen, even though I have a required option for it.
<form [formGroup]="cityForm" (submit)="submit()">
<mat-form-field>
<mat-label>Select City</mat-label>
<mat-select [(ngModel)]="city.Id"
[formControl]="cityFormControl"
[errorStateMatcher]="matcher">
<mat-option *ngFor="let c of dropdowns.Cities"
[value]="c.Id">
{{c.Name}}
</mat-option>
</mat-select>
<mat-error *ngIf="cityFormControl.hasError('required')">
City is <strong>required</strong>
</mat-error>
Controller code:
//Angular Imports
import { Component, Input, OnInit } from '@angular/core';
import { FormControl, FormGroup, FormGroupDirective, NgForm, Validators } from '@angular/forms';
import { ErrorStateMatcher } from '@angular/material/core';
@Component({
...
})
export class CityComponent implements OnInit {
city: any = {};
dropdowns: any = {};
// Form Control Variables
matcher = new MyErrorStateMatcher();
cityFormControl = new FormControl('', [Validators.required]);
cityForm = new FormGroup({
city: this.cityFormControl
});
constructor() {
}
ngOnInit(): void {
this.dropdowns = [
{Id: 1, Name: "Toronto"},
{Id: 2, Name: "Chicago"}
];
}
submit(form : FormGroup): void {
if (form.valid == false) {
//doesn't get called
return;
}
return;
}
/** Error when invalid control is dirty, touched, or submitted. */
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const isSubmitted = form && form.submitted;
return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
}
}
Any idea why the required validation is not working?
Best Answer
Refer to What are the practical differences between template-driven and reactive forms?
Please have a look at the following example: