如何在Angular 6中正确实现响应式表单自定义正则验证器?
Hey there! Let's break down what's causing that error and get your email validation working smoothly.
First: Why You're Seeing That Error
The Cannot read property 'pattern' of null error happens because when your form first loads (or before the user interacts with the email input), the errors property of the emailAddress control is null. Trying to access errors.pattern directly when errors is null throws the TypeError.
Step 1: Fix the Template Error Check
Instead of directly accessing errors.pattern, use Angular's hasError() method or the safe navigation operator (?.) to avoid the null reference. Here's how to update your template:
Option 1 (Recommended: Use hasError()):
<mat-form-field fxFlex> <input matInput placeholder="Email" formControlName="emailAddress"> <mat-error *ngIf="personForm.get('emailAddress').hasError('pattern')"> Invalid Email. </mat-error> <mat-error *ngIf="personForm.get('emailAddress').hasError('required')"> Email is required. </mat-error> </mat-form-field>
Option 2 (Safe Navigation Operator):
<mat-form-field fxFlex> <input matInput placeholder="Email" formControlName="emailAddress"> <mat-error *ngIf="personForm.controls['emailAddress'].errors?.pattern"> Invalid Email. </mat-error> </mat-form-field>
Note: Using personForm.get('emailAddress') is the preferred way to access form controls over personForm.controls['emailAddress'] in Angular.
Step 2: Ensure Your Email Pattern is Defined
Double-check that you've properly declared the emailPattern in your component class. If it's undefined or null, Validators.pattern() will fail silently (or cause unexpected issues). Here's a standard email regex you can use:
import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Component, OnInit } from '@angular/core'; export class ReactiveFormComponent implements OnInit { personForm: FormGroup; // Define your email pattern here emailPattern = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; constructor(private fb: FormBuilder) {} ngOnInit(): void { this.personForm = this.fb.group({ emailAddress: ['', [Validators.required, Validators.pattern(this.emailPattern)]] // Note: Angular 4+ doesn't require Validators.compose() - you can pass the array directly }); } }
Step 3: Implementing a Custom Regex Validator (Optional)
If you want more control over the validation logic (instead of using the built-in Validators.pattern), you can create a custom validator function:
Custom Validator Function:
import { AbstractControl, ValidationErrors } from '@angular/forms'; // Inside your component class customEmailValidator(control: AbstractControl): ValidationErrors | null { const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; // Only validate if the control has a value if (control.value && !emailRegex.test(control.value)) { return { invalidEmail: true }; // Return an error object with a custom key } return null; // Return null if validation passes }
Use the Custom Validator in Your Form:
ngOnInit(): void { this.personForm = this.fb.group({ emailAddress: ['', [ Validators.required, this.customEmailValidator.bind(this) // Bind the component context if needed ]] }); }
Update the Template for Custom Validator:
<mat-form-field fxFlex> <input matInput placeholder="Email" formControlName="emailAddress"> <mat-error *ngIf="personForm.get('emailAddress').hasError('required')"> Email is required. </mat-error> <mat-error *ngIf="personForm.get('emailAddress').hasError('invalidEmail')"> Invalid Email. Please enter a valid email address. </mat-error> </mat-form-field>
Final Notes
- Always check if
errorsexists before accessing its properties, or usehasError()to make your template more robust. - Angular 4+ allows passing an array of validators directly to the form control, so
Validators.compose()is no longer necessary. - Make sure your regex pattern is correct for your use case (adjust the TLD length if you need to support longer extensions like
.ioor.app).
内容的提问来源于stack exchange,提问作者monir tuhin

