Angular Material matInput

By Arvind Rai, September 14, 2018
Angular Material provides MatInput Directive to create <input> and <textarea> element. To use MatInput we need to import MatInputModule. MatInput provides errorStateMatcher property to assign ErrorStateMatcher object to control when to show validation error. Inputs are used with MatFormField that applies common underline, floating label and hint messages etc. We use <mat-label>, <mat-hint>, <mat-error> with <input matInput> and <textarea matInput> inside <mat-form-field>.
On this page we will create input text, color, date, time, number and textarea using reactive form as well as template-driven form.

Import MatInputModule

To work with Angular Material <input> and <textarea>, we need to import MatInputModule in application module.
import { MatInputModule } from '@angular/material/input';
 
@NgModule({
  imports: [
    ------
    MatInputModule
  ],
  ------
})
export class AppModule { } 

Use MatInput to create Inputs

Angular Material uses MatInput Directive to create <input> and <textarea> inside a <mat-form-field>. MatInput Directive selector is matInput. It is used with color, date, datetime-local, email, month, number, password, search, tel, text, time, url, week input types and textarea.
MatInput has following properties.
errorStateMatcher: This is ErrorStateMatcher object to control when error messages are shown.
readonly: This is Boolean value to know if element is readonly.
type: It gives input type of the element.
errorState: This is Boolean value to know if control is in error state or not.
Find the sample code snippet to create <input> and <textarea>.
1. Find the code snippet to create <input> using matInput selector.
<mat-form-field>
  <input matInput placeholder="Amount" 
      [formControl]="amount" 
      (change)="onAmountChange()">
</mat-form-field> 
Find the code snippet of TS file.
amount = new FormControl();
onAmountChange() {
  console.log(this.amount.value);
} 
2. Find the code snippet to create <textarea> using matInput selector.
<mat-form-field>
  <textarea matInput 
     placeholder="Comment" 
     [formControl]="commentFC" 
     (change)="onCommentChange()">
  </textarea>
</mat-form-field> 
Find the code snippet of TS file.
commentFC = new FormControl();
onCommentChange() {
  console.log(this.commentFC.value);
} 

Using <mat-form-field>

<input matInput> and <textarea matInput> are used inside <mat-form-field>. It applies common underline, floating label and hint messages etc. <mat-form-field> is used with <input matInput> as given below.
1. Using <mat-label>
<mat-form-field>
  <mat-label>Enter City</mat-label>
  <input matInput placeholder="City">
</mat-form-field> 
2. Using <mat-hint>
<mat-form-field>
  <mat-label>Enter City</mat-label>
  <input matInput placeholder="City">
  <mat-hint>Native place city</mat-hint>
</mat-form-field> 
3. Using <mat-error>
Suppose we have a FormControl object as following.
myCity = new FormControl('', Validators.required); 
Now find the HTML template code.
<mat-form-field>
  <mat-label>Enter City</mat-label>
  <input matInput placeholder="City" [formControl]="myCity">
  <mat-hint>Native place city</mat-hint>
  <mat-error *ngIf="myCity.hasError('required')">
    City is required.
  </mat-error>  
</mat-form-field> 
4. Using matPrefix and matSuffix
<mat-form-field>
  <mat-label>Enter Amount</mat-label>
  <input matInput placeholder="Amount" [formControl]="amount">
  <mat-hint>Indian Rupee</mat-hint>
  <span matPrefix>INR </span>
  <span matSuffix>.00</span>  
  <mat-error *ngIf="amount.hasError('required')">
    Amount is required.
  </mat-error>  
</mat-form-field> 
5. With <textarea matInput>
Suppose we have a FormControl object as following.
commentFC = new FormControl('', [
   Validators.required, 
   Validators.maxLength(30)
]); 
Now find the HTML template code to create textarea.
<mat-form-field>
  <mat-label>Write Your Comment</mat-label>
  <textarea matInput placeholder="Comment" 
       [formControl]="commentFC" #comment></textarea>
  <mat-hint align="end">{{comment.value?.length || 0}}/30</mat-hint>
  <mat-error *ngIf="commentFC.hasError('required')">
      Comment is required.
  </mat-error>
  <mat-error *ngIf="commentFC.hasError('maxlength')">
      Max length is 30.
  </mat-error>        
</mat-form-field> 

Validation of Input Text

We will validate input text here. We will validate for required, maximum value and minimum value of a number using Validators and FormControl. Find the code snippet of TS file.
amount = new FormControl('', [
  Validators.required,
  Validators.min(100),
  Validators.max(200)
]);
onAmountChange() {
  console.log(this.amount.value);
  console.log(this.amount.valid);
} 
Find the code snippet of HTML template.
<mat-form-field>
  <mat-label>Enter Amount</mat-label>
  <input matInput placeholder="Amount" [formControl]="amount" (change)="onAmountChange()">
  <mat-hint>Indian Rupee</mat-hint>
  <span matPrefix>INR </span>
  <span matSuffix>.00</span>  
  <mat-error *ngIf="amount.hasError('required')">
    Amount is required.
  </mat-error>  
  <mat-error *ngIf="amount.hasError('min')">
    Minimum Amount is 100.
  </mat-error>  
  <mat-error *ngIf="amount.hasError('max')">
    Maximum Amount is 200.
  </mat-error>        
</mat-form-field> 

Validation of Textarea

We will validate input <textarea> here. We will validate for required, maximum length using Validators and FormControl. Find the code snippet of TS file.
commentFC = new FormControl('', [
  Validators.required, 
  Validators.maxLength(30)
]);
onCommentChange() {
  console.log(this.commentFC.value);
  console.log(this.commentFC.valid);
} 
Find the code snippet of HTML template.
<mat-form-field>
  <textarea matInput 
      placeholder="Comment" 
      [formControl]="commentFC" 
      (change)="onCommentChange()">
  </textarea>
  <mat-hint align="end">{{commentFC.value?.length || 0}}/30</mat-hint>
  <mat-error *ngIf="commentFC.hasError('required')">
    Comment is required.
  </mat-error>
  <mat-error *ngIf="commentFC.hasError('maxlength')">
    Max length is 30.
  </mat-error>        
</mat-form-field> 

Find the print screen of the output for input and textarea.
Angular Material matInput

Using Custom ErrorStateMatcher

Angular Material provides ErrorStateMatcher to control when to show error. It has isErrorState() method that accepts FormControl and FormGroupDirective or NgForm as arguments and returns Boolean. To create custom ErrorStateMatcher class, we need to implement ErrorStateMatcher and override isErrorState(). If isErrorState() returns true, error will be shown and if false then error will not be shown. To use it with <input> and <textarea> input, MatInput Directive provides errorStateMatcher property. We need to assign the object of custom ErrorStateMatcher to errorStateMatcher property. Find our custom ErrorStateMatcher.
custom-error-state-matcher.ts
import { ErrorStateMatcher } from '@angular/material/core';
import { FormControl, FormGroupDirective, NgForm } from '@angular/forms';

export class CustomErrorStateMatcher implements ErrorStateMatcher {
    isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
      const isSubmitted = form && form.submitted;
      return (control.invalid && (control.dirty || control.touched || isSubmitted));
    }
} 
Our custom ErrorStateMatcher can be used for a <input> and <textarea> using errorStateMatcher property or globally for every <input> and <textarea> in the application.
a. To use errorStateMatcher property, we will create an instance of CustomErrorStateMatcher in TS file.
esMatcher = new CustomErrorStateMatcher(); 
Now use esMatcher object with errorStateMatcher property.
<mat-form-field>
  <mat-label>Enter Amount</mat-label>
  <input matInput placeholder="Amount" 
      [formControl]="amount" 
      [errorStateMatcher]="esMatcher"
      (change)="onAmountChange()">
  <mat-hint>Indian Rupee</mat-hint>
  <span matPrefix>INR </span>
  <span matSuffix>.00</span>  
  <mat-error *ngIf="amount.hasError('required')">
    Amount is required.
  </mat-error>  
  <mat-error *ngIf="amount.hasError('min')">
    Minimum Amount is 100.
  </mat-error>  
  <mat-error *ngIf="amount.hasError('max')">
    Maximum Amount is 200.
  </mat-error>        
</mat-form-field>

<br/>
<mat-form-field>
  <textarea matInput 
      placeholder="Comment" 
      [formControl]="commentFC" 
      [errorStateMatcher]="esMatcher"
      (change)="onCommentChange()">
  </textarea>
  <mat-hint align="end">{{commentFC.value?.length || 0}}/30</mat-hint>
  <mat-error *ngIf="commentFC.hasError('required')">
    Comment is required.
  </mat-error>
  <mat-error *ngIf="commentFC.hasError('maxlength')">
    Max length is 30.
  </mat-error>        
</mat-form-field> 
b. To use custom ErrorStateMatcher globally, configure provider in application module as following.
providers: [
  {provide: ErrorStateMatcher, useClass: CustomErrorStateMatcher}
] 
Now CustomErrorStateMatcher will be applied to all <input> and <textarea> element in the application. Angular material also provides ShowOnDirtyErrorStateMatcher that matches when a control is invalid and dirty.

Reactive Form Example with matInput

Find the complete code to create inputs using reactive form.
reactive-form.component.html
<h4>1. Input Text validation</h4>
<mat-form-field>
  <mat-label>Enter Amount</mat-label>
  <input matInput placeholder="Amount" 
      [formControl]="amount" 
      [errorStateMatcher]="esMatcher"
      (change)="onAmountChange()">
  <mat-hint>Indian Rupee</mat-hint>
  <span matPrefix>INR </span>
  <span matSuffix>.00</span>  
  <mat-error *ngIf="amount.hasError('required')">
    Amount is required.
  </mat-error>  
  <mat-error *ngIf="amount.hasError('min')">
    Minimum Amount is 100.
  </mat-error>  
  <mat-error *ngIf="amount.hasError('max')">
    Maximum Amount is 200.
  </mat-error>        
</mat-form-field>

<h4>2. Textarea validation</h4>
<mat-form-field>
  <textarea matInput 
      placeholder="Comment" 
      [formControl]="commentFC" 
      [errorStateMatcher]="esMatcher"
      (change)="onCommentChange()">
  </textarea>
  <mat-hint align="end">{{commentFC.value?.length || 0}}/30</mat-hint>
  <mat-error *ngIf="commentFC.hasError('required')">
    Comment is required.
  </mat-error>
  <mat-error *ngIf="commentFC.hasError('maxlength')">
    Max length is 30.
  </mat-error>        
</mat-form-field>

<h4>3. Textarea autosize</h4>
<mat-form-field>
  <textarea matInput 
      placeholder="Description" 
      [formControl]="descFC" 
      cdkTextareaAutosize
      cdkAutosizeMinRows="2"
      cdkAutosizeMaxRows="5"
      #autosize="cdkTextareaAutosize"
      (change)="onDescChange()">
  </textarea>
  <mat-error *ngIf="descFC.hasError('required')">
    Description is required.
  </mat-error>
</mat-form-field>

<h4>4. resizeToFitContent() and Reset() test</h4>
<div>
  <mat-form-field [style.fontSize]="fontSize.value">
    <textarea matInput 
        placeholder="Content" 
        [formControl]="contentFC" 
        cdkTextareaAutosize
        cdkAutosizeMinRows="2"
        cdkAutosizeMaxRows="5"
        #cfcAutosize="cdkTextareaAutosize">
    </textarea>
  </mat-form-field>
</div>
<div>   
  <button mat-raised-button (click)="resetTextAreaSize()">Reset Textarea Size</button>
</div>
<br/>
<div>  
  <mat-form-field>
    <mat-label>Select Font size</mat-label>
    <mat-select #fontSize value="15px" (selectionChange)="resizeTextArea()">
      <mat-option value="10px">10px</mat-option>
      <mat-option value="15px">15px</mat-option>
      <mat-option value="20px">20px</mat-option>
    </mat-select>
  </mat-form-field>
</div>

<h3>5. Person Reactive Form</h3>
<form [formGroup]="personForm" (ngSubmit)="onFormSubmit()">
  <div>
    <mat-form-field>
      <input matInput placeholder="Username" formControlName="username" [errorStateMatcher]="esMatcher">
      <mat-error *ngIf="username.hasError('required')">
        Username is required.
      </mat-error>
    </mat-form-field>  
  </div>
  <div>
    <mat-form-field>
      <input matInput type="password" formControlName="password" placeholder="Password" 
         [errorStateMatcher]="esMatcher">
      <mat-error *ngIf="password.hasError('required')">
        Password is required.
      </mat-error>
    </mat-form-field>
  </div>  
  <div>
    <mat-form-field>
      <textarea matInput 
          placeholder="Address" 
          formControlName="address" 
          cdkTextareaAutosize
          cdkAutosizeMinRows="2"
          cdkAutosizeMaxRows="4"          
          [errorStateMatcher]="esMatcher">
      </textarea>
      <mat-error *ngIf="address.hasError('required')">
        Comment is required.
      </mat-error>
      <mat-error *ngIf="address.hasError('maxlength')">
        Max length is 100.
      </mat-error>        
    </mat-form-field>
  </div>  
  <div>
    <mat-form-field>
      <input matInput type="color" formControlName="favColor" placeholder="Favorite color">
    </mat-form-field>
  </div>
  <div>
    <mat-form-field>                
      <input matInput type="date" formControlName="dob" placeholder="Date of birth">
    </mat-form-field>
  </div>
  <div>
    <mat-form-field>
      <input matInput type="time" formControlName="tob" placeholder="Time of birth">
    </mat-form-field>
  </div>   
  <div>
    <mat-form-field>
      <input matInput type="number" formControlName="age" placeholder="Age">
    </mat-form-field>
  </div>
  <div>   
    <button mat-raised-button>Submit</button>
  </div>  
</form> 
reactive-form.component.ts
import { Component, OnInit, ViewChild, NgZone } from '@angular/core';
import { FormControl, Validators, FormBuilder } from '@angular/forms';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { take } from 'rxjs/operators';

import { CustomErrorStateMatcher } from './custom-error-state-matcher';
import { PersonService } from './person.service';

@Component({
  selector: 'app-reactive',
  templateUrl: './reactive-form.component.html'
})
export class ReactiveFormComponent implements OnInit {
  constructor(private ngZone: NgZone,
        private formBuilder: FormBuilder,
        private personService: PersonService) {} 
  ngOnInit() {
  } 
  esMatcher = new CustomErrorStateMatcher();  
  //Input text validation
  amount = new FormControl('', [
    Validators.required,
    Validators.min(100),
    Validators.max(200)
  ]);
  onAmountChange() {
    console.log(this.amount.value);
    console.log(this.amount.valid);
  }
  //Textarea validation
  commentFC = new FormControl('', [
    Validators.required, 
    Validators.maxLength(30)
  ]);
  onCommentChange() {
    console.log(this.commentFC.value);
    console.log(this.commentFC.valid);
  }

  //Textarea autosize
  descFC = new FormControl('', [
    Validators.required
  ]);
  @ViewChild('autosize') 
  txtAreaAutosize: CdkTextareaAutosize;
  
  onDescChange() {
    console.log("enabled: "+ this.txtAreaAutosize.enabled);
    console.log("minRows: "+ this.txtAreaAutosize.minRows);
    console.log("maxRows: "+ this.txtAreaAutosize.maxRows);
    console.log("Description: "+ this.descFC.value);
  }

  //resizeToFitContent() and Reset() test
  contentFC = new FormControl();
  @ViewChild('cfcAutosize') 
  contentFCAutosize: CdkTextareaAutosize;

  resizeTextArea() {
    this.ngZone.onStable.pipe(take(1))
        .subscribe(() => this.contentFCAutosize.resizeToFitContent(true));
  }
  resetTextAreaSize() {
    this.contentFCAutosize.reset();
  }

  //Create a form
  personForm = this.formBuilder.group({
    username: ['', Validators.required],
    password: ['', Validators.required],
    address: ['', [Validators.required, Validators.maxLength(100)]],
    favColor: '#e66465',
    dob: '',
    tob: '',
    age: ''
  });
  onFormSubmit() {
    this.personService.savePerson(this.personForm.value);
  }
  get username() {
    return this.personForm.get('username');
  }  
  get password() {
    return this.personForm.get('password');
  }  

  get address() {
    return this.personForm.get('address');
  }    
} 
person.ts
export interface Person {
  username: string;
  password: string;
  address: string;
  favColor: string;
  dob: string;
  tob: string;
  age: number;
} 
person.service.ts
import { Injectable } from '@angular/core';
import { Person } from './person';

@Injectable({
  providedIn: 'root'
})
export class PersonService {
  savePerson(person: Person) {
     console.log(person);  
  }
} 

Find the print screen of the output.
Angular Material matInput

Template-Driven Form Example with matInput

Find the complete code to create inputs using template-driven form.
template-driven-form.component.html
<h3>6. Person Template-Driven Form</h3>
<form #personForm="ngForm" (ngSubmit)="onFormSubmit(personForm)">  
  <div>
    <mat-form-field>
      <input matInput placeholder="Username" 
      name="username" 
      required
      ngModel
      #name="ngModel"
      [errorStateMatcher]="esMatcher">
      <mat-error *ngIf="name.hasError('required')">
        Username is required.
      </mat-error>
    </mat-form-field>  
  </div>
  <div>
    <mat-form-field>
      <input matInput type="password" name="password" ngModel required placeholder="Password" 
         #pwd="ngModel" [errorStateMatcher]="esMatcher">
      <mat-error *ngIf="pwd.hasError('required')">
        Password is required.
      </mat-error>
    </mat-form-field>
  </div>  
  <div>
    <mat-form-field>
      <textarea matInput 
          placeholder="Address" 
          name="address" 
          required
          maxlength="100"
          ngModel
          #address="ngModel"
          cdkTextareaAutosize
          cdkAutosizeMinRows="2"
          cdkAutosizeMaxRows="4"          
          [errorStateMatcher]="esMatcher">
      </textarea>
      <mat-error *ngIf="address.hasError('required')">
        Comment is required.
      </mat-error>
    </mat-form-field>
  </div>  
  <div>
    <mat-form-field>
      <input matInput type="color" name="favColor" [ngModel]="'#e66465'" placeholder="Favorite color">
    </mat-form-field>
  </div>
  <div>
    <mat-form-field>                
      <input matInput type="date" name="dob" ngModel placeholder="Date of birth">
    </mat-form-field>
  </div>
  <div>
    <mat-form-field>
      <input matInput type="time" name="tob" ngModel placeholder="Time of birth">
    </mat-form-field>
  </div>   
  <div>
    <mat-form-field>
      <input matInput type="number" name="age" ngModel placeholder="Age">
    </mat-form-field>
  </div>  
  <div>   
    <button mat-raised-button>Submit</button>
  </div>  
</form> 
template-driven-form.component.ts
import { Component, OnInit } from '@angular/core';
import { CustomErrorStateMatcher } from './custom-error-state-matcher';
import { PersonService } from './person.service';

@Component({
  selector: 'app-template-driven',
  templateUrl: './template-driven-form.component.html'
})
export class TemplateDrivenFormComponent implements OnInit {
  constructor(private personService: PersonService) {} 
  ngOnInit() {
  } 
  esMatcher = new CustomErrorStateMatcher();  
  onFormSubmit(form) {
    this.personService.savePerson(form.value);
  } 
} 
app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <app-reactive></app-reactive>
    <app-template-driven></app-template-driven>
  ` 
})
export class AppComponent {
} 
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatButtonModule } from '@angular/material/button';

import { ErrorStateMatcher } from '@angular/material/core';

import { CustomErrorStateMatcher } from './custom-error-state-matcher';
import { AppComponent } from './app.component';
import { ReactiveFormComponent } from './reactive-form.component';
import { TemplateDrivenFormComponent } from './template-driven-form.component';

@NgModule({
  declarations: [
    AppComponent,
    ReactiveFormComponent,
    TemplateDrivenFormComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    FormsModule,    
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatSelectModule,
    MatButtonModule
  ],
  providers: [
   // {provide: ErrorStateMatcher, useClass: CustomErrorStateMatcher}
  ],
  bootstrap: [AppComponent]
})
export class AppModule { } 
styles.css
@import "~@angular/material/prebuilt-themes/indigo-pink.css"; 

References

Angular Material Input
CdkTextareaAutosize Directive

Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us