mat-select required validation not working
Asked Answered
S

7

22

I have the following code

<form #createForm="ngForm">
 <mat-form-field>
   <mat-select placeholder="Favorite food"
      matInput
     [ngModel]
     food="food"
     #food="ngModel" required>
    <mat-option *ngFor="let food of foods" [value]="food.value">
      {{ food.viewValue }}
    </mat-option>
   </mat-select>
</mat-form-field>
</form>
<button [disabled]="!createForm.valid">submit</button>

Since I want the "selection" is a required field, the "submit" button should be disabled when the form is rendered. However, the "submit" button is enabled when the form is displayed. What is the problem?

Saprolite answered 28/3, 2018 at 23:8 Comment(2)
Are you missing the name attribute to the mat-select? Like this is mandatory.. In my case this works.. <form #myForm="ngForm"> <mat-select name="journal_bank_id" placeholder="Bank Account" [(ngModel)]="journal.journal_bank_id" required><mat-option>--</mat-option><mat-option *ngFor="let bank of bank_accounts | async" [value]="bank.bank_id">{{bank.bank_account_number }}</mat-option></mat-select><button mat-raised-button type="submit" color="primary" (click)="save()" [disabled]='myForm.invalid'>Save</button>Mayan
It should work more or less. stackblitz.com/edit/angular-azgehlFundus
D
16

This works for me when I (a) use a name attribute and (b) use the two-way ngModel binding syntax.

i.e. Instead of this

<mat-select placeholder="Favorite food" matInput [ngModel] food="food" #food="ngModel" required>

use this:

<mat-select name="food" placeholder="Favorite food" [(ngModel)]="food" required>

Dancy answered 29/6, 2018 at 2:41 Comment(1)
two way binding does the trick, there's no need to use name attribute in order to make it workOffutt
M
5

for validation in angular 5 use reactive forms. refer this

*** componenet.ts *******

import { FormControl, Validators, FormBuilder, FormGroup, ReactiveFormsModule, NgForm } from '@angular/forms';

export class Test implements OnInit{
foodform:FormGroup;
 constructor(){}

ngOnInit() {
// create form group of controls 
 this.foodform = new FormGroup({
   favoriteFood: new FormControl('', [Validators.required])
 });
}
}

**** Component.html************

   <form #createForm="ngForm" [formGroup]="foodform ">
     <mat-form-field>
       <mat-select placeholder="Favorite food"
          matInput
         [ngModel]
         food="food"
         #food="ngModel"  formControlName="favoriteFood">
        <mat-option *ngFor="let food of foods" [value]="food.value" >
          {{ food.viewValue }}
        </mat-option>
       </mat-select>
      <mat-error *ngIf="foodform.controls['favoriteFood'].hasError('required') && foodform.controls['favoriteFood'].pristine">
                Required Message
      </mat-error>
    </mat-form-field>
    </form>

use [formGroup] and formControlName in your html form.

Moia answered 29/3, 2018 at 5:16 Comment(6)
I don't use reactive form and I am using template based component. Your answer doesn't solve my problem.Saprolite
Correct this is not your answer when using template-driven forms.Mayan
This is the same as my question. The only thing differ from there is there is some more stuff in the component file.// create form group of controls this.foodform = new FormGroup({ favoriteFood: new FormControl('', [Validators.required]) });Saprolite
It will add a * correctly, but it does not prevent "submit" enabled.Saprolite
I was able to solve the problem by writing a validation directive which checks if there is a value in the control and display an error if none. However, the directive doesn't add "*". I ended up using both "required" and my new validation directive.Saprolite
This answer indirectly states that template driven forms are somehow depracated in Angular 5 which is not true. Does not fix original issue neither.Fundus
U
3

The only way required field validation works on a mat-select is by using reactive form validation. Just import the respective components in typescript file:

import {FormControl, Validators} from '@angular/forms';

HTML file :

Remove your ngModel reference

<mat-form-field>
   <mat-select placeholder="Favorite food"
      matInput [formControl]="foodControl"     
     required>
    <mat-option *ngFor="let food of foods" [value]="food.value">
      {{ food.viewValue }}
    </mat-option>
   </mat-select>
</mat-form-field>

This works for the required field validation. If you wanted to validate more probably you will end up accessing the form in the typescript file. Its weird that there is no option to do form validation, this is the only way i found to make it work.

Upheave answered 16/4, 2018 at 18:28 Comment(0)
F
0

Look at danger89's comment under your original question. You are missing the name attribute. E.g:

<form #createForm="ngForm" (ngSubmit)="submitFunction(createForm)">
      <mat-form-field>
          <mat-select 
            placeholder="Favorite food"
            ngModel
            name="food"
            required
          >
            <mat-option *ngFor="let food of foods" [value]="food.value">
              {{ food.viewValue }}
            </mat-option>
          </mat-select>
      </mat-form-field>
      <button type="submit" [disabled]="!createForm.valid">submit</button>
  </form>

Because of the name attribute, your food.value can now be found at createForm.value.food when submitting the form.

Fisherman answered 27/4, 2018 at 7:58 Comment(0)
D
0

This worked for me: Import ReactiveFormsModule in you app module

import { ReactiveFormsModule } from '@angular/forms';

and add its dependency in @NgModule decorator

Dieppe answered 9/1, 2019 at 6:55 Comment(0)
R
0

I don't know what I'm doing wrong but I can't get any solution to work using Ang8 + Material8 and a multi-select while using a FormGroup and a FormControl. I ended up doing the following as a workaround.

First I added a tag to the mat-select, #thisselect

Then I tested the value of the tag for zero length in the submit button

<form [formGroup]="bypartForm" (ngSubmit)="onSubmit()">
            <mat-form-field [hideRequiredMarker]="true">
                <mat-select #thisselect placeholder="Brands" formControlName="brands"
                    (selectionChange)="selectChanged($event)" multiple required>
                    <mat-option *ngFor="let brand of brandList" [value]="brand.name">{{brand.name}}</mat-option>
                </mat-select>
            </mat-form-field>
            <mat-form-field [hideRequiredMarker]="true">
                <input matInput autocomplete="off" placeholder="Part#" formControlName="part" required>
            </mat-form-field>
            <div class="form-buttons">
                <button mat-raised-button color="primary" type="submit" [disabled]="!bypartForm.valid || (thisselect.value != undefined && thisselect.value.length == 0)">Submit</button>
            </div>
        </form>
Rajasthani answered 2/12, 2019 at 15:33 Comment(0)
V
0

I had same problem like you, and ReactiveForms is not a valid solution for me. I solved it by adding ngModel AND value to the mat-input, in addition to what is mentioned above, the attribute name is very important, your code would end like this:

<form #createForm="ngForm">
 <mat-form-field>
   <mat-select placeholder="Favorite food"
      matInput
     [(ngModel)]="yourResult.foodId"
     [(value)]="yourResult.foodId"
     name="foodselect"
     required>
    <mat-option *ngFor="let food of foods" [value]="food.foodId">
      {{ food.viewValue }}
    </mat-option>
   </mat-select>
   <mat-error 
   *ngIf="createForm.controls['foodselect'].hasError('required')">
   This is required
 </mat-error>
</mat-form-field>
</form>
<button [disabled]="!createForm.valid">submit</button>
Venireman answered 11/2, 2024 at 16:53 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.