Overview
The third chapter introduces angular form controls, how to create a form in Angular, and how to validate data against form controls.
Corresponding official document address:
- Introduction to Angular Forms
- Reactive form
- Template-driven forms
- Form validation
Angular-practice/SRC /forms-overview
Contents
- Angular from pit to pit – Getting Started with Angular usage
- Angular From Pothole to Pothole – Component eating Guide
- Angular From pothole to Pothole – Form controls overview
Knowledge Graph
Step by Step
Introduction of the form
It is used to process the user’s input. By capturing the user’s input event from the view and verifying whether the user’s input meets the conditions, the data model in the form model modification component is created to obtain the user’s input data
Template-driven forms | Reactive form | |
---|---|---|
Set up the form | Implicitly create form control instances by components | Create control instances that are displayed in the component class |
Form validation | instruction | function |
Template-driven forms update their data by modifying the ngModel bound data model when the form data changes, whereas reactive forms return a new data model when the form data changes, rather than directly modifying the original data model
Template-driven forms
Interaction with the user is accomplished by binding data values and behavior constraints on the user (a field must be filled in, a field is too long) to the component’s template using form-specific directives (such as ngModel for two-way data binding)
Bidirectional data binding for template-driven forms
Import FormsModule in the root module and add it to the imports array of the root module
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
/ / introduce FormsModule
import { FormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { TemplateDrivenFormsComponent } from './template-driven-forms/template-driven-forms.component';
@NgModule({
declarations: [
AppComponent,
ReactiveFormsComponent,
DynamicFormsComponent,
TemplateDrivenFormsComponent
],
imports: [
BrowserModule,
AppRoutingModule,
FormsModule // Add it to the application module
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Copy the code
Create a new class file to hold data information for two-way data binding between components and templates
ng g class classes/hero
Copy the code
export class Hero {
/** * ctor * @param name Name * @param age * @param gender * @param location Address */
constructor(public name: string.public age: number.public gender: string.public location: string) {}}Copy the code
Create the form information that holds the data in the component’s template, and use ngModel to complete the two-way data binding between the component and the template
<form>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" name="name" id="name" [(ngModel)] ="hero.name" class="form-control" autocomplete="off" required minlength="4">
</div>
<div class="form-group">
<label for="age">Age:</label>
<input type="number" name="age" id="age" [(ngModel)] ="hero.age" class="form-control" required>
</div>
<div class="form-group">
<label for="gender">Gender:</label>
<div class="form-check" *ngFor="let gender of genders">
<input class="form-check-input" type="radio" name="gender" id="{{gender.id}}" value="{{gender.value}}"
[(ngModel)] ="hero.gender">
<label class="form-check-label" for="{{gender.id}}">
{{gender.text}}
</label>
</div>
</div>
<div class="form-group">
<label for="location">Address:</label>
<select name="location" id="location" [(ngModel)] ="hero.location" class="form-control" required>
<option value="{{location}}" *ngFor="let location of locations">{{location}}</option>
</select>
</div>
<button type="submit" (click) ="submit()" class="btn btn-primary">Submit</button>
</form>
<p>Form of data message: {{hero | json}}</p>
Copy the code
import { Component, OnInit } from '@angular/core';
import { Hero } from '. /.. /classes/hero';
@Component({
selector: 'app-template-driven-forms',
templateUrl: './template-driven-forms.component.html',
styleUrls: ['./template-driven-forms.component.scss']})export class TemplateDrivenFormsComponent implements OnInit {
constructor() {}// Gender option
public genders = [{
id: 'male', text: 'male', value: true
}, {
id: 'female', text: 'woman', value: false
}];
/** * Address drop down */
public locations: Array<string> = ['beijing'.'shanghai'.'hangzhou'.'wuhan'];
hero = new Hero(' '.18.'true'.'beijing');
ngOnInit(): void {
}
submit() {
}
}
Copy the code
When using ngModel for template binding, Angular automatically appends an NgForm directive to the form tag because the NgForm directive controls elements in the form with the ngModel directive and the name attribute. The name property is the key angular uses to register controls, so it must be added when using ngModel for two-way data binding in forms
Tracks the state of form controls
After using ngModel in the form, the ngModel directive reflects the state of the control by updating its CSS class
state | The CSS class when this occurs | CSS classes that did not occur |
---|---|---|
Control accessed | ng-touched | ng-untouched |
The value of the control changes | ng-dirty | ng-pristine |
Control whether the value is valid | ng-valid | ng-invalid |
Using CSS class styles for these controls, you can add custom CSS styles to prompt users when their input does not meet the criteria
.ng-valid[required]..ng-valid.required {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
}
Copy the code
Validation of data
When you need to validate user input, add a native HTML form validator to the control to set the validation criteria. When the form control’s data changes, Angular instructs the data to generate a list of error messages
During validation of user input data, ngModel is exposed by adding a template reference variable to the control to get state information about the specified control in the template, which can then be fed back by getting a list of error messages
<div class="form-group">
<label for="name">Name:</label>
<! Get the state of the control by exposing the ngModel directive as a template reference variable.
<input type="text" name="name" id="name" [(ngModel)] ="hero.name" class="form-control" autocomplete="off" required
minlength="4" #name="ngModel">
<! Verify the validity of data only after the user has changed the data or accessed the control.
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">The name cannot be empty</div>
<div *ngIf="name.errors.minlength">The name cannot contain less than 4 characters</div>
</div>
</div>
Copy the code
In the case of data verification failure, the form is not allowed to submit for the system. Therefore, the submission event can be bound to the ngSubmit event attribute of the form, and the data validity can be judged at the submit button in the form of template reference variables. If invalid, the submit button of the form will be disabled
<form (ngSubmit) ="submit()" #heroForm="ngForm">
<div class="form-group">
<label for="name">Name:</label>
<! Get the state of the control by exposing the ngModel directive as a template reference variable.
<input type="text" name="name" id="name" [(ngModel)] ="hero.name" class="form-control" autocomplete="off" required
minlength="4" #name="ngModel">
<! Verify the validity of data only after the user has changed the data or accessed the control.
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">The name cannot be empty</div>
<div *ngIf="name.errors.minlength">The name cannot contain less than 4 characters</div>
</div>
</div>
<div class="form-group">
<label for="age">Age:</label>
<input type="number" name="age" id="age" [(ngModel)] ="hero.age" class="form-control" required>
</div>
<div class="form-group">
<label for="gender">Gender:</label>
<div class="form-check" *ngFor="let gender of genders">
<input class="form-check-input" type="radio" name="gender" id="{{gender.id}}" value="{{gender.value}}"
[(ngModel)] ="hero.gender">
<label class="form-check-label" for="{{gender.id}}">
{{gender.text}}
</label>
</div>
</div>
<div class="form-group">
<label for="location">Address:</label>
<select name="location" id="location" [(ngModel)] ="hero.location" class="form-control" required>
<option value="{{location}}" *ngFor="let location of locations">{{location}}</option>
</select>
</div>
<button type="submit" [disabled] =! "" heroForm.form.valid" class="btn btn-primary">Submit</button>
</form>
Copy the code
Reactive form
Quick learning
Reactive forms rely on the ReactiveFormsModule module, so they need to be introduced in the root module before they can be used
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
/ / introduce ReactiveFormsModule
import { ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ReactiveFormsComponent } from './reactive-forms/reactive-forms.component';
@NgModule({
declarations: [
AppComponent,
ReactiveFormsComponent,
DynamicFormsComponent,
TemplateDrivenFormsComponent
],
imports: [
BrowserModule,
AppRoutingModule,
ReactiveFormsModule // Add it to the application module
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Copy the code
When reactive forms are used, an instance of the FormControl class corresponds to a FormControl. When used, you assign the instance of the control to a property, and you can later track the value and state of the FormControl by listening on this custom property
import { Component, OnInit } from '@angular/core';
// Introduce the FormControl object
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
// Define attributes to take on FormControl instances
public name = new FormControl(' ');
constructor() { }
ngOnInit(): void{}}Copy the code
Once the control instance is created in the component, you associate the control instance with the form controls in the template by adding the formControl property binding to the form controls on the view template
<form>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" [formControl] ='name' class="form-control" autocomplete="off">
</div>
</form>
<div>The name controls data values: {{name | json}}</div>
Copy the code
You can get a copy of the data values of the current FormControl by using the value property of the FormControl, and update the FormControl values by using the setValue method
import { Component, OnInit } from '@angular/core';
// Introduce the FormControl object
import { FormControl } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
// Define attributes to take on FormControl instances
public name = new FormControl('12345');
constructor() { }
ngOnInit(): void {
}
getName() {
alert(this.name.value);
}
setName() {
this.name.setValue(1111111); }}Copy the code
Compose multiple controls through FomGroup
A form cannot have only one control, so the unified management of multiple form controls can be achieved by constructing a FormGroup instance in the component
With FormGroup, you also define a property in the component to host the control group instance, and then add each control in the control group as a property value to the instance
import { Component, OnInit } from '@angular/core';
// Introduce FormControl and FormGroup objects
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
// Define object attributes to hold the FormGroup instance
public profileForm = new FormGroup({
name: new FormControl('La la la la'),
age: new FormControl(12)});constructor() { }
ngOnInit(): void{}}Copy the code
In the view template, bind the properties of the following FormGroup instance to the form element using the FormGroup directive, and then bind each property of the control group to the corresponding form control using the formControlName
<form [formGroup] ='profileForm'>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" formControlName='name' class="form-control" autocomplete="off" required minlength="4">
</div>
<div class="form-group">
<label for="age">Age:</label>
<input type="number" id="age" formControlName='age' class="form-control" autocomplete="off" required step="1"
max="100" min="1">
</div>
</form>
<div>FormGroup group controls the value of the form: {{profileForm. Value | json}}</div>
Copy the code
When building complex forms, you can make the form more structured by nesting the FormGroup within the FormGroup
import { Component, OnInit } from '@angular/core';
// Introduce FormControl and FormGroup objects
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
// Define object attributes to hold the FormGroup instance
public profileForm = new FormGroup({
name: new FormControl('La la la la'),
age: new FormControl(12),
address: new FormGroup({
province: new FormControl('Beijing'),
city: new FormControl('Beijing'),
district: new FormControl('Chaoyang district'),
street: new FormControl('Sanlitun Street')})});constructor() { }
ngOnInit(): void {
}
submit() {
alert(JSON.stringify(this.profileForm.value)); }}Copy the code
In the view template, bind the FormGroup instance in the FormGroup control group to the control by using the formGroupName property
<form [formGroup] ='profileForm' (ngSubmit) ='submit()'>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" formControlName='name' class="form-control" autocomplete="off" required minlength="4">
</div>
<div class="form-group">
<label for="age">Age:</label>
<input type="number" id="age" formControlName='age' class="form-control" autocomplete="off" required step="1"
max="100" min="1">
</div>
<div formGroupName='address'>
<div class="form-group">
<label for="province">Save:</label>
<input type="text" id="province" formControlName='province' class="form-control" autocomplete="off" required>
</div>
<div class="form-group">
<label for="city">City:</label>
<input type="text" id="city" formControlName='city' class="form-control" autocomplete="off" required>
</div>
<div class="form-group">
<label for="district">Area:</label>
<input type="text" id="district" formControlName='district' class="form-control" autocomplete="off" required>
</div>
<div class="form-group">
<label for="street">Street:</label>
<input type="text" id="street" formControlName='street' class="form-control" autocomplete="off" required>
</div>
</div>
<button type="submit" class="btn btn-primary" [disabled] =! "" profileForm.valid">The data submitted</button>
</form>
<div>FormGroup group controls the value of the form: {{profileForm. Value | json}}</div>
Copy the code
For forms that use FormGroup, when using setValue to update data, you must ensure that the new data structure is the same as the original structure, otherwise an error will be reported
import { Component, OnInit } from '@angular/core';
// Introduce FormControl and FormGroup objects
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
// Define object attributes to hold the FormGroup instance
public profileForm = new FormGroup({
name: new FormControl('La la la la'),
age: new FormControl(12),
address: new FormGroup({
province: new FormControl('Beijing'),
city: new FormControl('Beijing'),
district: new FormControl('Chaoyang district'),
street: new FormControl('Sanlitun Street')})});constructor() { }
ngOnInit(): void {
}
submit() {
alert(JSON.stringify(this.profileForm.value));
}
updateProfile() {
this.profileForm.setValue({
name: '423'}); }}Copy the code
In some cases, we just want to update the data value of a certain control in the control group. In this case, we need to use patchValue to update
import { Component, OnInit } from '@angular/core';
// Introduce FormControl and FormGroup objects
import { FormControl, FormGroup } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
// Define object attributes to hold the FormGroup instance
public profileForm = new FormGroup({
name: new FormControl('La la la la'),
age: new FormControl(12),
address: new FormGroup({
province: new FormControl('Beijing'),
city: new FormControl('Beijing'),
district: new FormControl('Chaoyang district'),
street: new FormControl('Sanlitun Street')})});constructor() { }
ngOnInit(): void {
}
submit() {
alert(JSON.stringify(this.profileForm.value));
}
updateProfile() {
this.profileForm.patchValue({
name: '12345'}); }}Copy the code
Use FormBuilder to generate form controls
When there are too many controls, it can be difficult to build the FormControl manually through FormGroup or FormControl, so we can use dependency injection FormBuilder class to simplify the form construction
The FormBuilder service has three methods: Control, Group, and Array to generate FormControl, FormGroup, and FormArray, respectively, in the component class
The value of each control name is an array. The first value is the default value of the control. The second and third items are synchronous and asynchronous validation methods for this value
import { Component, OnInit } from '@angular/core';
// Introduce FormBuilder to build the form control
import { FormBuilder } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
/** * ctor * @param formBuilder */
constructor(private formBuilder: FormBuilder) {}public profileForm = this.formBuilder.group({
name: ['La la la la'],
age: [12],
address: this.formBuilder.group({
province: ['Beijing'],
city: ['Beijing'],
district: ['Chaoyang district'],
street: ['Sanlitun Street']})}); ngOnInit():void{}}Copy the code
Validation of data
In the same way that template-driven forms validate data, you can use native form validators in reactive forms. When setting rules, you change the second parameter of the data value corresponding to the control name in the template to the validated rule
In reactive forms, the data source comes from the component class, so you should add the validator function directly to the corresponding FormControl constructor in the component class. Angular then calls these functions whenever control data changes
Getter methods are created for the specified control to get state information about the specified control in the template
import { Component, OnInit } from '@angular/core';
// Introduce FormBuilder to build the form control
import { FormBuilder } from '@angular/forms';
// Introduce the Validators validator
import { Validators } from '@angular/forms';
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
/** * ctor * @param formBuilder */
constructor(private formBuilder: FormBuilder) {}public profileForm = this.formBuilder.group({
name: [' ', [
Validators.required,
Validators.minLength(4)
]],
age: [12],
address: this.formBuilder.group({
province: ['Beijing'],
city: ['Beijing'],
district: ['Chaoyang district'],
street: ['Sanlitun Street']})});// Add the getter method to validate the control to get the state value in the template
get name() {
return this.profileForm.get('name');
}
ngOnInit(): void{}}Copy the code
<form [formGroup] ='profileForm' (ngSubmit) ='submit()'>
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" formControlName='name' class="form-control" autocomplete="off" required minlength="4">
<! Verify the validity of data only after the user has changed the data or accessed the control.
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">The name cannot be empty</div>
<div *ngIf="name.errors.minlength">The name cannot contain less than 4 characters</div>
</div>
</div>
<div class="form-group">
<label for="age">Age:</label>
<input type="number" id="age" formControlName='age' class="form-control" autocomplete="off" required step="1"
max="100" min="1">
</div>
<div formGroupName='address'>
<div class="form-group">
<label for="province">Save:</label>
<input type="text" id="province" formControlName='province' class="form-control" autocomplete="off" required>
</div>
<div class="form-group">
<label for="city">City:</label>
<input type="text" id="city" formControlName='city' class="form-control" autocomplete="off" required>
</div>
<div class="form-group">
<label for="district">Area:</label>
<input type="text" id="district" formControlName='district' class="form-control" autocomplete="off" required>
</div>
<div class="form-group">
<label for="street">Street:</label>
<input type="text" id="street" formControlName='street' class="form-control" autocomplete="off" required>
</div>
</div>
<button type="button" class="btn btn-primary" (click) ="updateProfile()">Update the information</button>
<button type="submit" class="btn btn-primary" [disabled] =! "" profileForm.valid">The data submitted</button>
</form>
<div>FormGroup group controls the value of the form: {{profileForm. Value | json}}</div>
Copy the code
Custom data validation for forms
Custom validators
In many cases, the native validation rules cannot meet our needs, so we need to create a custom validator to achieve
For reactive forms, you can define a method that validates the control’s data and then add the method as a parameter to the control definition
import { Component, OnInit } from '@angular/core';
// Introduce FormBuilder to build the form control
import { FormBuilder } from '@angular/forms';
// Introduce the Validators validator
import { Validators } from '@angular/forms';
/** * Custom validation method * @param name control information */
function validatorName(name: FormControl) {
return name.value === 'lala' ? { nameinvalid: true } : null;
}
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
/** * ctor * @param formBuilder */
constructor(private formBuilder: FormBuilder) {}public profileForm = this.formBuilder.group({
name: [' ', [
Validators.required,
Validators.minLength(4),
validatorName // Add a custom validation method
]],
age: [12],
address: this.formBuilder.group({
province: ['Beijing'],
city: ['Beijing'],
district: ['Chaoyang district'],
street: ['Sanlitun Street']})});// Add the getter method to validate the control to get the state value in the template
get name() {
return this.profileForm.get('name');
}
ngOnInit(): void{}}Copy the code
In the validation method, null is returned when the data is valid, and an object message is returned when the data is invalid. In this case, nameInvalid is the key value of the error message obtained in the template
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" formControlName='name' class="form-control" autocomplete="off" required minlength="4">
<! Verify the validity of data only after the user has changed the data or accessed the control.
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">The name cannot be empty</div>
<div *ngIf="name.errors.minlength">The name cannot contain less than 4 characters</div>
<div *ngIf="name.errors.nameinvalid">Name is invalid</div>
</div>
</div>
Copy the code
In template-driven forms, since you are not using a FormControl instance directly, you should add a custom directive to the template to validate the control data
Use the Angular CLI to create a directive for form validation
ng g directive direactives/hero-validate
Copy the code
After creating the directive, we need to add the Validator to the existing Validator collection, and to integrate the directive with Angular forms, we need to inherit the Validator interface
import { Directive, Input } from '@angular/core';
import { AbstractControl, Validator, ValidationErrors, NG_VALIDATORS } from '@angular/forms';
@Directive({
selector: '[appHeroValidate]'.Use multi: true to add the validator to the existing set of validators
providers: [{ provide: NG_VALIDATORS, useExisting: HeroValidateDirective, multi: true}]})export class HeroValidateDirective implements Validator {
constructor() {}/** * Performs synchronous validation on the specified control * @param control */
validate(control: AbstractControl): ValidationErrors | null {
return control.value === 'lala' ? { 'nameInvalid': true } : null; }}Copy the code
When the inherited validate method is implemented, you can add this directive to the controls of the template
<div class="form-group">
<label for="name">Name:</label>
<! Get the state of the control by exposing the ngModel directive as a template reference variable.
<input type="text" name="name" id="name" [(ngModel)] ="hero.name" class="form-control" autocomplete="off" required
minlength="4" #name="ngModel" appHeroValidate>
<! Verify the validity of data only after the user has changed the data or accessed the control.
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">The name cannot be empty</div>
<div *ngIf="name.errors.minlength">The name cannot contain less than 4 characters</div>
<div *ngIf="name.errors.nameInvalid">Name is invalid</div>
</div>
</div>
Copy the code
Cross-validation across fields
When you need to cross-validate multiple control data in a form, you need to validate the entire FormGroup. So the validation method here needs to be passed in as a FormGroup parameter when the control group is defined
Similar to the validation of a single field, the ValidatorFn interface is implemented to return null if the form data is valid and ValidationErrors otherwise
import { Component, OnInit } from '@angular/core';
// Introduce FormControl and FormGroup objects
import { FormControl, FormGroup, ValidatorFn, ValidationErrors } from '@angular/forms';
// Introduce FormBuilder to build the form control
import { FormBuilder } from '@angular/forms';
// Introduce the Validators validator
import { Validators } from '@angular/forms';
/** * cross-field validation * @param controlGroup controlGroup */
const nameAgeCrossValidator: ValidatorFn = (controlGroup: FormGroup): ValidationErrors | null= > {
// Get information about the child control
//
const name = controlGroup.get('name');
const age = controlGroup.get('age');
return name && age && name.value === 'lala' && age.value === 12 ? { 'nameAgeInvalid': true } : null;
};
@Component({
selector: 'app-reactive-forms',
templateUrl: './reactive-forms.component.html',
styleUrls: ['./reactive-forms.component.scss']})export class ReactiveFormsComponent implements OnInit {
/** * ctor * @param formBuilder */
constructor(private formBuilder: FormBuilder) {}public profileForm = this.formBuilder.group({
name: [' ', [
Validators.required,
Validators.minLength(4),
validatorName
]],
age: [12],
address: this.formBuilder.group({
province: ['Beijing'],
city: ['Beijing'],
district: ['Chaoyang district'],
street: ['Sanlitun Street']
})
}, { validators: [nameAgeCrossValidator] }); // Add validators for control groups
ngOnInit(): void{}}Copy the code
When cross-validation is performed against multiple fields, the template page needs to obtain the error information by obtaining the error object information of the entire form
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" formControlName='name' class="form-control" autocomplete="off" required minlength="4">
<! Verify the validity of data only after the user has changed the data or accessed the control.
<div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
<div *ngIf="name.errors.required">The name cannot be empty</div>
<div *ngIf="name.errors.minlength">The name cannot contain less than 4 characters</div>
<div *ngIf="name.errors.nameinvalid">Name is invalid</div>
</div>
</div>
<div class="form-group">
<label for="age">Age:</label>
<input type="number" id="age" formControlName='age' class="form-control" autocomplete="off" required step="1"
max="100" min="1">
<div *ngIf="profileForm.errors? .nameAgeInvalid && (profileForm.touched || profileForm.dirty)"
class="alert alert-danger">Lala can't be 12</div>
</div>
Copy the code
For template-driven forms, custom directives are used for cross-field validation, as opposed to validation for a single control. In this case, you need to add directives to the form tag and then use template reference variables to retrieve error information
import { Directive } from '@angular/core';
import { Validator, AbstractControl, ValidationErrors, ValidatorFn, FormGroup, NG_VALIDATORS } from '@angular/forms';
/** * cross-field validation * @param controlGroup controlGroup */
const nameAgeCrossValidator: ValidatorFn = (controlGroup: FormGroup): ValidationErrors | null= > {
// Get information about the child control
//
const name = controlGroup.get('name');
const age = controlGroup.get('age');
return name && age && name.value === 'lala' && age.value === 12 ? { 'nameAgeInvalid': true } : null;
};
@Directive({
selector: '[appCrossFieldValidate]',
providers: [{ provide: NG_VALIDATORS, useExisting: CrossFieldValidateDirective, multi: true}]})export class CrossFieldValidateDirective implements Validator {
constructor() { }
validate(control: AbstractControl): ValidationErrors | null {
returnnameAgeCrossValidator(control); }}Copy the code
Of the pit
Personal Profile: Born in 1996, born in a fourth-tier city in Anhui province, graduated from Top 10 million universities. .NET programmer, gunslinger, cat. It will begin in December 2016. NET programmer career, Microsoft. NET technology stalwart, aspired to be the cloud cat kid programming for Google the best. NET programmer. Personal blog: yuiter.com blog garden blog: www.cnblogs.com/danvic712