How to quickly get started with VUE3.0: Entering to learn
Angular provides two different methods to handle user input through forms:响应式表单
and模板驱动表单
. [Related tutorial recommendation: "Angular Tutorial"]
Only responsive forms are introduced here. For template-driven forms, please refer to the official website:
https://angular.cn/guide/forms-overview#setup-in-template-driven-forms
to use the responsive form control , you need to import ReactiveFormsModule
from the @angular/forms
package and add it to the imports
array of your NgModule
. As follows: app.module.ts
/***** app.module.ts *****/ import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ imports: [ // other imports ... ReactiveFormsModule ], }) export class AppModule { }
There are three steps to use form control.
Register the reactive form module in your app. This module declares some directives that you want to use in reactive forms.
Generate a new FormControl
instance and save it in the component.
Register this FormControl
in the template.
To register a form control, import the FormControl
class and create a new instance of FormControl
, saving it as a property of the class. As follows: test.component.ts
/***** test.component.ts *****/ import { Component } from '@angular/core'; import { FormControl } from '@angular/forms'; @Component({ selector: 'app-name-editor', templateUrl: './name-editor.component.html', styleUrls: ['./name-editor.component.css'] }) export class TestComponent { // You can set the initial value in the constructor of FormControl, in this example it is the empty string name = new FormControl(''); }
Then register the control in the template as follows: test.component.html
<!-- test.component.html --> <label> Name: <input type="text" [formControl]="name"> </label> <!-- If the value entered in input changes, the value displayed here will also change --> <p>name: {{ name.value }}</p>
For other properties and methods of
FormControl
, please refer to the API reference manual .https://angular.cn/api/forms/FormControl#formcontrol
Just like an instance of FormControl
allows you to control the control corresponding to a single input box, an instance of FormGroup
can also track a group of FormControl
instances (such as form status of a form). When FormGroup
is created, each control in it is tracked by its name.
See the following example demonstration: test.component.ts
, test.component.html
import { Component } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms' @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.component.css'] }) export class TestComponent implements OnInit { constructor() {} profileForm = new FormGroup({ firstName: new FormControl('', [Validators.required,Validators.pattern('[a-zA-Z0-9]*')]), lastName: new FormControl('', Validators.required), }); onSubmit() { // Check the values of each field in the control group console.log(this.profileForm.value) } }
<!-- profileForm This FormGroup is bound to the form element through the FormGroup directive, creating a communication layer between the model and the input box in the form --> <!-- The FormGroup directive also listens to the submit event emitted by the form element and emits an ngSubmit event, allowing you to bind a callback function. --> <form [formGroup]="profileForm" (ngSubmit)="onSubmit()"> <label> <!-- The FormControlName directive binds each input box to the form control FormControl defined in the FormGroup. These form controls will communicate with the corresponding elements --> First Name: <input type="text" formControlName="firstName"> </label> <label> Last Name: <input type="text" formControlName="lastName"> </label> <button type="submit" [disabled]="!profileForm.valid">Submit</button> </form> <p>{{ profileForm.value }}</p> <!-- The status of the control group: INVALID or VALID --> <p>{{ profileForm.status }}</p> <!-- Whether the value entered by the control group is a valid value: true or false--> <p>{{ profileForm.valid }}</p> <!-- Whether to disable: true or false--> <p>{{ profileForm.disabled }}</p>
For other properties and methods of
FormGroup
, please refer to the API reference manual .https://angular.cn/api/forms/FormGroup#formgroup
. In responsive forms, when you need to deal with multiple forms, manually creating multiple form control instances will be very tedious. The FormBuilder
service provides some convenience methods to generate form controls. FormBuilder
creates and returns these instances in the same way behind the scenes, it's just simpler to use.
FormBuilder
is an injectable service provider provided by ReactiveFormModule
. This dependency can be injected by simply adding it to the component's constructor.
The
FormBuilder
service has three methods:control()
,group()
andarray()
. These methods are factory methods for generatingFormControl
,FormGroup
andFormArray
respectively in the component class.
See the following example: test.component.ts
import { Component } from '@angular/core'; // 1. Import FormBuilder import { FormBuilder, Validators } from '@angular/forms'; @Component({ selector: 'app-test', templateUrl: './test.component.html', styleUrls: ['./test.component.css'] }) export class TestComponent { // 2. Inject the FormBuilder service constructor(private fb: FormBuilder) { } ngOnInit() { } profileForm = this.fb.group({ firstName: ['', [Validators.required, Validators.pattern('[a-zA-Z0-9]*')]], lastName: ['', Validators.required], }); // Equivalent to // profileForm = new FormGroup({ // firstName: new FormControl('', [Validators.required,Validators.pattern('[a-zA-Z0-9]*')]), // lastName: new FormControl('', Validators.required), // }); onSubmit() { console.log(this.profileForm.value) console.log(this.profileForm) } }
By comparison, it can be found that using the FormBuilder
service can more conveniently generate FormControl
, FormGroup
and FormArray
without having to manually create a new
instance every time.
For a complete API list of
Validators
class validators, refer to the API manualhttps://angular.cn/api/forms/Validators.
The validator ( Validators
) function can be a synchronous function or an asynchronous function.
FormControl
.Promise
or Observable
, which later emits a set of validation errors or null. They can be passed in as the third parameter when instantiating FormControl
.For performance reasons, Angular will not run asynchronous validators until all synchronous validators have passed. These validation errors are set after each asynchronous validator has been executed.
https://angular.cn/api/forms/Validators
class Validators { static min(min: number): ValidatorFn // The minimum value allowed to be entered static max(max: number): ValidatorFn // The maximum value static required(control: AbstractControl): ValidationErrors | null // Whether it is required static requiredTrue(control: AbstractControl): ValidationErrors | null static email(control: AbstractControl): ValidationErrors | null // Whether it is an email format static minLength(minLength: number): ValidatorFn // Minimum length static maxLength(maxLength: number): ValidatorFn // Maximum length static pattern(pattern: string | RegExp): ValidatorFn // Regular match static nullValidator(control: AbstractControl): ValidationErrors | null // Do nothing static compose(validators: ValidatorFn[]): ValidatorFn | null static composeAsync(validators: AsyncValidatorFn[]): AsyncValidatorFn | null }
import { Validators } from '@angular/forms';
when instantiating the FormControl
control
... ngOnInit(): void { this.heroForm = new FormGroup({ // Instantiate the FormControl control name: new FormControl(this.hero.name, [ Validators.required, // Validation, required Validators.minLength(4), // The length is not less than 4 forbiddenNameValidator(/bob/i) // Custom validator]), alterEgo: new FormControl(this.hero.alterEgo), power: new FormControl(this.hero.power, Validators.required) }); } get name() { return this.heroForm.get('name'); } get power() { return this.heroForm.get('power'); }
For the content of custom validator, please refer to the API manual
https://angular.cn/guide/form-validation
Sometimes built-in validation The processor cannot meet the needs very well. For example, we need to verify a form and the input value can only be the value in a certain array, and the value in this array changes in real time as the program runs. At this time, the built-in The validator cannot meet this requirement, and a custom validator needs to be created.
Add custom validators in responsive forms. In the built-in validator section above, there is a forbiddenNameValidator
function as follows:
import { Validators } from '@angular/forms'; ... ngOnInit(): void { this.heroForm = new FormGroup({ name: new FormControl(this.hero.name, [ Validators.required, Validators.minLength(4), // 1. Add custom validator forbiddenNameValidator(/bob/i) ]) }); } // 2. Implement a custom validator whose function is to prohibit the input of values with bob string export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const forbidden = nameRe.test(control.value); // 3. Return null when the value is valid, or return the verification error object when it is invalid return forbidden ? {forbiddenName: {value: control.value}} : null; }; }
The validator returns
null
if the value is valid, or验证错误对象
if it is invalid. Authentication error objects usually have an attribute called the authentication key (forbiddenName
). Its value is an arbitrary dictionary that you can use to insert error messages ({name}).
Add custom validators in template-driven forms. To add a directive to the template, the directive contains the validator
function. At the same time, this directive needs to register itself as the provider of NG_VALIDATORS
. As shown below:
// 1. Import related classes import { NG_VALIDATORS, Validator, AbstractControl, ValidationErrors } from '@angular/forms'; import {Input} from '@angular/core' @Directive({ selector: '[appForbiddenName]', // 2. Register as a provider of NG_VALIDATORS token providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}] }) export class ForbiddenValidatorDirective implements Validator { @Input('appForbiddenName') forbiddenName = ''; // 3. Implement the validator interface, that is, implement the validate function validate(control: AbstractControl): ValidationErrors | null { // Return null when the value is valid, or return the validation error object when it is invalid return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control) : null; } } // 4. Custom verification function export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { const forbidden = nameRe.test(control.value); // 3. Return null when the value is valid, or return the verification error object when it is invalid return forbidden ? {forbiddenName: {value: control.value}} : null; }; }
Note that custom validation directives are instantiated with
useExisting
instead ofuseClass
. IfuseClass
is used instead ofuseExisting
, a new class instance will be registered, but it will not haveforbiddenName
.
<input type="text" required appForbiddenName="bob" [(ngModel)]="hero.name">