In Angular, there are two types of forms,模板驱动
and模型驱动
. [Recommended related tutorials: "Angular Tutorial"]
1.1 Overview
控制逻辑
of the form is written in组件模板
, which is suitable for简单
form types.
1.2 Get started quickly
1). Introduce the dependent module FormsModule
import { FormsModule } from "@angular/forms" @NgModule({ imports: [FormsModule], }) export class AppModule {}
2) Convert the DOM form to ngForm
<form #f="ngForm" (submit)="onSubmit(f)"></form>
3) Declare the form field as ngModel
<form #f= "ngForm" (submit)="onSubmit(f)"> <input type="text" name="username" ngModel /> <button>Submit</button> </form>
4). Get the form field value
import { NgForm } from "@angular/forms" export class AppComponent { onSubmit(form: NgForm) { console.log(form.value) // {username: ''} } }
5), form grouping
<form #f="ngForm" (submit)="onSubmit(f)"> <div ngModelGroup="user"> <input type="text" name="username" ngModel /> </div> <div ngModelGroup="contact"> <input type="text" name="phone" ngModel /> </div> <button>Submit</button> </form>
import { NgForm } from "@angular/forms" export class AppComponent { onSubmit(form: NgForm) { console.log(form.value) // {contact: {phone: ''}, user:{username: ''}} } }
1.3 Form validation
<form #f="ngForm" (submit)="onSubmit(f)"> <input type="text" name="username" ngModel required pattern="d" /> <button>Submit</button> </form>
export class AppComponent { onSubmit(form: NgForm) { // Check whether the entire form is verified through console.log(form.valid) } }
<!-- Disable form submission when the entire form fails validation --> <button type="submit" [disabled]="f.invalid">Submit</button>
displays the error message when the form item fails in the component template.
<form #f="ngForm" (submit)="onSubmit(f)"> <input #username="ngModel" /> <div *ngIf="username.touched && !username.valid && username.errors"> <div *ngIf="username.errors.required">Please fill in the username</div> <div *ngIf="username.errors.pattern">Does not conform to regular rules</div> </div> </form>
Specifies the style when the form item fails validation.
input.ng-touched.ng-invalid { border: 2px solid red; }
2.1 Overview
控制逻辑
of the form is written in组件类
, which has more control over the verification logic and is suitable for复杂
form types.
In a model-driven form, the form field needs to be an instance of FormControl
class. The instance object can验证表单字段
, whether the value has been modified, etc.
A set of form fields constitutes the entire form, and the entire form needs to be an instance of FormGroup
class, which can perform整体
validation on the form.
FormControl: a form item in a form group.
FormGroup: a form group. The form is at least one FormGroup.
FormArray: used for complex forms. It can dynamically add form items or form groups. During form validation, one item in the FormArray fails and the whole fails. .
2.2 Get started quickly
1), introduce ReactiveFormsModule
import { ReactiveFormsModule } from "@angular/forms" @NgModule({ imports: [ReactiveFormsModule] }) export class AppModule {}
2). Create the FormGroup form control object in the component class
import { FormControl, FormGroup } from "@angular/forms" export class AppComponent { contactForm: FormGroup = new FormGroup({ name: new FormControl(), phone: new FormControl() }) }
3). Form in associated component template
<form [formGroup]="contactForm" (submit)="onSubmit()"> <input type="text" formControlName="name" /> <input type="text" formControlName="phone" /> <button>Submit</button> </form>
4). Get the form value
export class AppComponent { onSubmit() { console.log(this.contactForm.value) } }
5). Set the form default value
contactForm: FormGroup = new FormGroup({ name: new FormControl("Default value"), phone: new FormControl(15888888888) })
6), form grouping
contactForm: FormGroup = new FormGroup({ fullName: new FormGroup({ firstName: new FormControl(), lastName: new FormControl() }), phone: new FormControl() })
<form [formGroup]="contactForm" (submit)="onSubmit()"> <div formGroupName="fullName"> <input type="text" formControlName="firstName" /> <input type="text" formControlName="lastName" /> </div> <input type="text" formControlName="phone" /> <button>Submit</button> </form>
onSubmit() { console.log(this.contactForm.value.name.username) console.log(this.contactForm.get(["name", "username"])?.value) }
2.3 FormArray
requirements: A group of contact information is displayed on the page by default, and more contact information groups can be added by clicking the button.
import { Component, OnInit } from "@angular/core" import { FormArray, FormControl, FormGroup } from "@angular/forms" @Component({ selector: "app-root", templateUrl: "./app.component.html", styles: [] }) export class AppComponent implements OnInit { // form contactForm: FormGroup = new FormGroup({ contacts: new FormArray([]) }) get contacts() { return this.contactForm.get("contacts") as FormArray } //Add contact information addContact() { //Contact information const myContact: FormGroup = new FormGroup({ name: new FormControl(), address: new FormControl(), phone: new FormControl() }) //Add contact information to the contact information array this.contacts.push(myContact) } // Delete contact information removeContact(i: number) { this.contacts.removeAt(i) } ngOnInit() { //Add default contact information this.addContact() } onSubmit() { console.log(this.contactForm.value) } }
<form [formGroup]="contactForm" (submit)="onSubmit()"> <div formArrayName="contacts"> <div *ngFor="let contact of contacts.controls; let i = index" [formGroupName]="i" > <input type="text" formControlName="name" /> <input type="text" formControlName="address" /> <input type="text" formControlName="phone" /> <button (click)="removeContact(i)">Remove contact information</button> </div> </div> <button (click)="addContact()">Add contact information</button> <button>Submit</button> </form>
2.4 Built-in form validator
1) Use the validation rules provided by the built-in validator to validate the form fields
import { FormControl, FormGroup, Validators } from "@angular/forms" contactForm: FormGroup = new FormGroup({ name: new FormControl("Default value", [ Validators.required, Validators.minLength(2) ]) })
2). Get whether the entire form has passed the verification
onSubmit() { console.log(this.contactForm.valid) }
<!-- Disable form buttons when the entire form fails verification --> <button [disabled]="contactForm.invalid">Submit</button>
3). Display the error message when verification is passed in the component template
get name() { return this.contactForm.get("name")! }
<form [formGroup]="contactForm" (submit)="onSubmit()"> <input type="text" formControlName="name" /> <div *ngIf="name.touched && name.invalid && name.errors"> <div *ngIf="name.errors.required">Please fill in your name</div> <div *ngIf="name.errors.maxlength"> The name length cannot be greater than {{ name.errors.maxlength.requiredLength }}. The actual length is {{ name.errors.maxlength.actualLength }} </div> </div> </form>
2.5 Custom synchronous form validator
The type of custom validator is the TypeScript class
. The class contains specific verification methods. The verification method must be a static method.
The verification method has a parameter control, of type AbstractControl. In fact, it is the type of the instance object of the FormControl class.
If the verification is successful, null is returned.
If the verification fails, the object is returned. The attribute in the object is the verification identification, and the value is true, indicating that the verification failed.
The return value of the verification method is ValidationErrors | null
import { AbstractControl, ValidationErrors } from "@angular/forms" export class NameValidators { // Field values cannot contain spaces static cannotContainSpace(control: AbstractControl): ValidationErrors | null { // Verification failed if (/s/.test(control.value)) return { cannotContainSpace: true } //Verification passed return null } }
import { NameValidators } from "./Name.validators" contactForm: FormGroup = new FormGroup({ name: new FormControl("", [ Validators.required, NameValidators.cannotContainSpace ]) })
<div *ngIf="name.touched && name.invalid && name.errors"> <div *ngIf="name.errors.cannotContainSpace">Name cannot contain spaces</div> </div>
2.6 Custom asynchronous form validator
import { AbstractControl, ValidationErrors } from "@angular/forms" import { Observable } from "rxjs" export class NameValidators { static shouldBeUnique(control: AbstractControl): Promise<ValidationErrors | null> { return new Promise(resolve => { if (control.value == "admin") { resolve({ shouldBeUnique: true }) } else { resolve(null) } }) } }
contactForm: FormGroup = new FormGroup({ name: new FormControl( "", [ Validators.required ], NameValidators.shouldBeUnique ) })
<div *ngIf="name.touched && name.invalid && name.errors"> <div *ngIf="name.errors.shouldBeUnique">Duplicate username</div> </div> <div *ngIf="name.pending">Detecting whether names are duplicates</div>
2.7 FormBuilder
快捷
to create a form.
this.fb.control
: form item
this.fb.group
: form group, the form is at least one FormGroup
this.fb.array
: used for complex forms, you can dynamically add form items or form groups, during form validation, there is a FormArray The item failed and the whole failed.
import { FormBuilder, FormGroup, Validators } from "@angular/forms" export class AppComponent { contactForm: FormGroup constructor(private fb: FormBuilder) { this.contactForm = this.fb.group({ fullName: this.fb.group({ firstName: ["", [Validators.required]], lastName: [""] }), phone: [] }) } }
2.8 Monitoring changes in form values
In actual work, we often need to perform corresponding processing based on changes in a form value. Generally, we can use ngModalChange
or a form to achieve
2.8.1 ngModalChange
<div> <input type="text" [(ngModal)]="name" (ngModalChange)="nameChange()" /> </div>
import { FormControl, FormGroup } from "@angular/forms" export class AppComponent { public name = 'a'; public nameChange() { } }
Angular officially does not recommend using ngModalChange.
2.8.2 Form control
<div [formGroup]="contactForm"> <input type="text" formControlName="name" /> </div>
import { FormControl, FormGroup } from "@angular/forms" export class AppComponent { contactForm: FormGroup = new FormGroup({ name: new FormControl() }) ngOnInt() { this.contactForm.get("name").valueChanges.subscribe(data => { console.log(data); } } }
2.9 Exercise
1), Get the selected value in a group of check boxes
<form [formGroup]="form" (submit)="onSubmit()"> <label *ngFor="let item of Data"> <input type="checkbox" [value]="item.value" (change)="onChange($event)" /> {{ item.name }} </label> <button>Submit</button> </form>
import { Component } from "@angular/core" import { FormArray, FormBuilder, FormGroup } from "@angular/forms" interface Data { name: string value: string } @Component({ selector: "app-checkbox", templateUrl: "./checkbox.component.html", styles: [] }) export class CheckboxComponent { Data: Array<Data> = [ { name: "Pear", value: "pear" }, { name: "Plum", value: "plum" }, { name: "Kiwi", value: "kiwi" }, { name: "Apple", value: "apple" }, { name: "Lime", value: "Lime" } ] form: FormGroup constructor(private fb: FormBuilder) { this.form = this.fb.group({ checkArray: this.fb.array([]) }) } onChange(event: Event) { const target = event.target as HTMLInputElement const checked = target.checked const value = target.value const checkArray = this.form.get("checkArray") as FormArray if (checked) { checkArray.push(this.fb.control(value)) } else { const index = checkArray.controls.findIndex( control => control.value === value ) checkArray.removeAt(index) } } onSubmit() { console.log(this.form.value) } }
2). Get the value selected in the radio button
export class AppComponent { form: FormGroup constructor(public fb: FormBuilder) { this.form = this.fb.group({ gender: "" }) } onSubmit() { console.log(this.form.value) } }
<form [formGroup]="form" (submit)="onSubmit()"> <input type="radio" value="male" formControlName="gender" /> Male <input type="radio" value="female" formControlName="gender" /> Female <button type="submit">Submit</button> </form>
2.10 Other
patchValue: Set the value of the form control (you can set all, or you can set one of them, the others are not affected)
setValue: Set the value of the form control (set all, cannot exclude any one)
valueChanges: When the form
event is triggered when the value of the control changes
: the form content is blanked