Angular Material's Mat-select component is experiencing issues with the Form Control functionality

I have implemented a mat-select form element linked to a FormControl for validation purposes. The desired outcome is to display an error message below the element if the select box is left empty or nothing is selected.

However, upon submitting the form without selecting an option, it still registers as valid even though I have set it as required.

<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:

//Code snippet for Angular
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;  
}

/** Custom error state matcher for handling invalid controls */
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));
    }
}

Can anyone provide insights on why the required validation is not functioning as expected?

Answer №1

Make sure to include the control name and then rely on the material form to manage any errors by using the valid function on the designated control.

<form [formGroup]="cityForm" (submit)="submit()">

<mat-form-field>
   <mat-label>Select City</mat-label>

   <mat-select formControlName="cityFormControl"  // Form group is established in form tag
               [compareWith]="CompareCity">       // You must create a comparison method
                <mat-option *ngFor="let c of dropdowns.Cities"
                            [value]="c.Id">
                    {{c.Name}}
                </mat-option>
   </mat-select>

   <mat-error *ngIf="!cityForm.controls['cityFormControl'].valid && cityForm.controls['cityFormControl'].touched">
     City is <strong>required</strong>
   </mat-error>

A compare function might appear as follows:

  public CompareCity(Param1: City, Param2: City) : boolean {
    return Param1 && Param2 ? Param1.Id === Param2.Id : false;
  }

Answer №2

For detailed insights on the differences between template-driven and reactive forms, check out this resource.

Take a look at the code snippet below for an example:

constructor(private fb: FormBuilder) { }

cityForm: FormGroup;

ngOnInit(): void {
  this.cityForm = this.fb.group({
    city: ['', [Validators.required]]
  })
}
get city() { return this.cityForm.get("city") }
<form [formGroup]="cityForm" (submit)="submit()">
  <mat-select [formControl]="city" [errorStateMatcher]="matcher">
    <mat-option *ngFor="let c of dropdowns.Cities" [value]="c.Id">
      {{c.Name}}
    </mat-option>
  </mat-select>

  <mat-error *ngIf="city.hasError('required')">
    City is <strong>required</strong>
  </mat-error>
</form>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What are the benefits of utilizing pipe, map, and catchError in Angular?

While working on Angular 8 code created by another developer, I came across this method: retrieveByExperience(experienceId: number): Observable<any[]> { return this.http.get<OrganisationCode[]>(environment.serverUrl + `api/expert/experienc ...

What is the significance of parentheses when used in a type definition?

The index.d.ts file in React contains an interface definition that includes the following code snippet. Can you explain the significance of the third line shown below? (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | nu ...

Angular 2 Release Candidate 1 introduces a powerful router that allows for URL rewriting capabilities

Since updating to routing rc 1, my application is encountering issues when the URL includes query string parameters. Below is the setup of the routes in the app component: import {Component, OnInit, OnDestroy } from '@angular/core'; import {RO ...

Obtaining JSON data in React Native without prior knowledge of the key

When I receive this type of data, the keys are common but the items vary. How can I extract and add this data to my list of categories? { "99": "Venues", "100": "Party Supplies", "101": "Enter ...

Making the right choice: Class vs Interface in your Angular project

Today, I find myself pondering a question regarding classes and interfaces in Angular. In my opinion, here is my take on the matter: Interfaces are utilized in Typescript for type-checking purposes, existing until transpilation and disappearing in produc ...

Customize the position of nodes and their descendants in a d3 tree chart by setting specific x and y coordinates

I am in need of a d3 tree structure that looks like this. https://i.sstatic.net/X6U3u.png There are two key points to understand from the image above: Headers will have multiple parents(wells). I need to be able to drag and drop links connecting w ...

Utilizing the Teams web app within my customized electron application

I've been developing an electron app and am trying to integrate the MS Teams web app into it. I've successfully displayed MS Word, MS Powerpoint, and other apps using window.loadURL(''), but I'm experiencing issues with MS Teams. D ...

Having trouble utilizing the Visual Studio Code debugger in an Express.js project that uses TypeScript

My package.json file is shown below: ` { "name": "crm-backend", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev" ...

Encountering errors while adding Storybook to a TypeScript-react project with existing stories

I recently added storybook to my TypeScript React project, but I encountered an error when running yarn storybook. The issue seems to be related to the "as" keyword in the generated code. -- Error message Parsing error: Missing semicolon 10 | back ...

Navigating to the tsconfig.json file based on the location of the file being linted

In my monorepo, each package currently contains a .eslintrc.cjs file with the following setup: Package-specific ESLint Configuration const path = require('path') const ts = require('typescript') const OFF = 0 const WARN = 1 const ERROR ...

The error code TS2345 indicates that the Argument 'OperatorFunction<Object, Object>' cannot be assigned to the parameter 'OperatorFunction'

Can you assist me in resolving this issue? Angular CLI: 14.0.2 Node: 16.13.0 rxjs: 7.5.5 typescript: 4.7.4 These are my imports: import { Observable, BehaviorSubject } from "rxjs"; import { first, catchError, tap } from "rxjs/operators" ...

Preserve data on page even after refreshing in Angular

Upon opening my website, I expect to see "Finance/voucher" at the top. However, after refreshing the page, only "Finance" appears which is not what I want. I need it to always display "Finance/voucher" even after a page refresh. I have included all the r ...

Error encountered while compiling React application: Module build unsuccessful due to failure in ./node_modules/babel-loader/lib/index.js

Having an issue while trying to compile a React app. After pulling the repo from Github, running yarn install, and then compiling it, I encountered the following error: Module build failed (from ./node_modules/babel-loader/lib/index.js) SyntaxError: {file_ ...

Using HttpClient to retrieve data in formats other than JSON

Error Encountered While Trying to Download Excel File via API I attempted to download an Excel file through an API using a specific method, but unfortunately, I encountered the following error: SyntaxError: Unexpected token P in JSON at position 0 at J ...

Step-by-step guide to implementing a user-friendly search input field using the powerful AngularJS material design framework

I am searching for an effortless method to implement a feature similar to the expandable search text field in angular-mdl. By clicking on a search button, it will expand into a text field. <!-- Expandable Textfield --> <form action="#"> < ...

The Angular 5 animations enter transition successfully performs (void => state) but encounters issues with the leave transition (state => void)

Currently tackling a challenge in Angular 5 where I am trying to build a custom carousel image browser from scratch. The goal is to allow users to navigate through images by clicking or swiping to view the next or previous image. The animations for the :e ...

The Angular translation service may encounter issues when used on different routes within the application

I'm currently working on an Angular application that has multi-language support. To better organize my project, I decided to separate the admin routes from the app.module.ts file and place them in a separate file. However, after doing this, I encounte ...

How to adjust the font size in the Angular Material Select Panel?

One way to customize the appearance of a panel in CSS is by using the panelClass attribute. <mat-form-field appearance="fill"> <mat-label>Toppings</mat-label> <mat-select [formControl]="toppings" panelClass=&quo ...

What is the best way to utilize a service that has been imported using forRoot() within a feature module

Currently utilizing the package found at: https://github.com/troyanskiy/ng2-resource-rest, I am encountering difficulties when attempting to correctly import it into my feature modules. The documentation provides the following instructions: @NgModule({ ...

Utilize Angular 2 to upload and access files directly on the client side

How can I obtain log file(s) from a user so that I can analyze them? Is there a way to create a drop area where the user can upload a file, and then I can read it using JavaScript? I am currently using Angular2 rc5 and have node.js running on the backend, ...