1. Template driver
The control logic of the form is written in the component template, which is more suitable for simple form types.
(1) Create a simple form
- It needs to be introduced in the component class
FormsModule
and define a submission method
import {
Component} from '@angular/core';
import {
FormsModule} from "@angular/forms";
@Component({
selector: 'app-layout',
templateUrl: './layout.component.html',
})
export class LayoutComponent {
onSubmit(value: any) {
console.log(value);
}
}
- In the component template, by
#myForm="ngForm"
defining this form asAngular
a form, you can useAngular
the features provided in the form. Bind the submit event to this form. For form controls, you need to setname
properties as unique indexes and setngModel
properties to achieve two-way data binding with the form object.
<form #myForm="ngForm" (submit)="onSubmit(myForm)">
<input type="text" name="username" ngModel />
<button type="submit">Submit</button>
</form>
- In the web page, enter a piece of text, click the submit button, and check that the submit event receives
value
anngForm
object, which containsform.value
the data source of the two-way binding of the control. The properties of the form controlname
serve as the keys andvalue
values of the data source. Only the input value of the setngModel
control will be recordedform.value
in
(2) Form grouping
When a large number of form items are needed, the form items can be managed in groups.
- In the component template, by
ngModelFroup
grouping, the group name will be stored in the form object as a direct attribute name.
Here, if the elements used for grouping are replacedng-container
, they will not be rendered into real elements.
<form #myForm="ngForm" (submit)="onSubmit(myForm)">
<h3>用户信息</h3>
<div ngModelGroup="user">
名字:<input type="text" name="username" ngModel />
年龄:<input type="number" name="age" ngModel />
</div>
<h3>车辆注册信息</h3>
<div ngModelGroup="car">
品牌:<input type="text" name="brand" ngModel />
颜色:<input type="color" name="color" ngModel />
</div>
<button type="submit">Submit</button>
</form>
- Fill out the form and click Submit to view the console
form.value
:
(3) Form verification
Angular
Several common validation rules provided by forms:
- required required field
- minlength minimum length
- maxlength maximum length
- pattern regular verification
- In the component template, add the rules that need to be verified on the form items that need to be verified.
名字:<input type="text" name="username" ngModel pattern="\d" maxlength="10"/>
年龄:<input type="number" name="age" ngModel required/>
- In the component class, when submitting, you can
form.valid
check whether the form verification passes through the attribute (Boolean)
onSubmit(form: any) {
console.log(form.valid);
}
- For the submit button, you can restrict the click when form.valid is false.
!myForm.valid
can be written asmyForm.invalid
<button type="submit" [disabled]="!myForm.valid">Submit</button>
- When the verification fails, you can
HTML
add prompt information in
. When you need a single form item to display its own prompt information, you must first get the individual form item and#username=’ngModel‘
get the form item;
username
the type is to get the form itemNgMdel
based on the attribute.touched
Click or enter;
touched
the property will change wheninput
the mouse is moved into and out of the boxtrue
;
invalid
the property gets whether the form item fails the verification;
errors
the property stores the information of all failed verification items.
名字:<input #username='ngModel' type="text" required name="username" pattern="\d*" ngModel maxlength="10"/>
<button type="submit">Submit</button>
<div *ngIf="username.touched && username.invalid && username.errors" style="color: red">
<div *ngIf="username.errors['required']">用户名必填</div>
<div *ngIf="username.errors['pattern']">用户名必须是数字</div>
<div *ngIf="username.errors['maxlength']">用户名最大长度为10</div>
</div>
2. Model driven
The control logic of the form is written in the component class, which is more flexible for operations such as form verification and is more suitable for complex forms.
A model-driven form is an FormGroup
instance of a class that can validate the form as a whole; each form item is an FormControl
instance of a class that can validate individual form items and monitor changes to form values.
(1) Create a form
- In the module to which the component belongs,
ReactiveFormsModule
the module needs to be introduced and added toimports
the array
import {
ReactiveFormsModule} from "@angular/forms";
@NgModule({
...
imports: [
...
ReactiveFormsModule
],
...
})
- In the component class, you need to introduce the required modules, define the current form as an
FormGroup
instance of the class, and define each form item asFormControl
an instance of the class
...
import {
FormGroup, FormControl} from "@angular/forms";
...
export class LayoutComponent {
public form: FormGroup = new FormGroup({
username: new FormControl(),
age: new FormControl(),
});
onSubmit() {
console.log(this.form);
}
}
- In the component template, the current form uses
formGroup
attributes to bind the instances defined in the component classFormGroup
, and the form items useformControllName
binding to eachFormControl
instance;formGroup
the binding is an object, so brackets are needed;formControllName
the binding is a string, so no need Square brackets.
<form [formGroup]="form" (submit)="onSubmit()">
名字:<input type="text" formControlName="username"/>
年龄:<input type="number" formControlName="age"/>
<button type="submit">Submit</button>
</form>
- Enter the form items, click Submit, and take a look at the output
this.form
data structure.
(2) Form grouping
- In the component class, form grouping can be achieved by
FormGroup
creating an object inside the object.FormGroup
public form: FormGroup = new FormGroup({
user: new FormGroup({
username: new FormControl(),
age: new FormControl(),
}),
car: new FormControl()
});
- In the component template, the group uses
formGroupName
the name of the binding group
<form [formGroup]="form" (submit)="onSubmit()">
<ng-container formGroupName="user">
名字:<input type="text" formControlName="username"/>
年龄:<input type="number" formControlName="age"/>
</ng-container>
车辆:<input type="text" formControlName="car"/>
<button type="submit">Submit</button>
</form>
(3) Dynamically create forms: FormArray
FormArray
Used to dynamically add a set of form items. The entire form form
needs to be bound to an FormGroup
instance object. Within this instance object FormControl
, objects (a single form item), FormGroup
objects (a group of form items), or FormArray
objects (a group of dynamically added form items) can be placed.
- In the component class,
FormGroup
create an attribute in the instance object bound to the current form. The type isFormArray
, and each element in it is oneFormGroup
. Initialize an element.
public carForm: FormGroup = new FormGroup({
cars: new FormArray([
new FormGroup({
name: new FormControl(),
power: new FormControl()
})
])
});
- In component template
- By
formArrayName
binding the property name of this object, two-way data binding between the template and object dataFormArray
can be achieved .FormArray
FormArray
The attribute of the instancecontrols
is an array that saves the data of the dynamically added form group.*ngFor
Since it is an array, it needs to be bound when rendering .controls
Each item of is anFormGroup
instance object, so for each item, you need to use the attributeFormGroupName
bound to the current element.index
- Each
FormGroup
instance object and the form items inside it are allFormControl
instance objects, so you need to useFormControlName
the binding attribute name.
<form [formGroup]="carForm" (submit)="onSubmit()">
<div formArrayName="cars">
<div *ngFor="let car of cars.controls; let i = index" [formGroupName]="i">
<input formControlName="name" placeholder="Car name">
<input formControlName="power" placeholder="Car power">
</div>
</div>
</form>
FormArray
It is suitable for dynamically adding form groups, so we need a button to trigger the operation of adding a form group. And,FormArray
a method to add an element to the object.FormArray
The object'spush
methods addFormArray
an element to the object.
<button (click)="addCar()">增加一组表单</button>
addCar() {
const cars = this.carForm.get('cars') as FormArray;
cars.push(new FormGroup({
name: new FormControl(),
power: new FormControl()
}));
}
- For
cars
this variable, you need to get it every time you add a form, so you can define itcars
as aget
formal variable.this.cars
This way you can accesscars
the instance object directlyFromArray
.
get cars(): FormArray {
return this.carForm.get('cars') as FormArray;
}
- When you need to delete a dynamically added form group, in the component template, each dynamically added
FormGroup
object needs a delete button to trigger the delete operation and pass the currentFormGroup
objectindex
to it; in the component class, you need to call the methodFromArray
of the objectremoveAt
, deleteformGroup
the object at the specified index.
<div *ngFor="let car of cars.controls; let i = index" [formGroupName]="i">
<input formControlName="name" placeholder="Car name">
<input formControlName="power" placeholder="Car power">
<button (click)="removeCar(i)">Remove</button>
</div>
removeCar(i: number) {
// 从cars中删除第i个元素。比数组删除元素方便
this.cars.removeAt(i);
}
- Add
submit
an event to print the current form when submittingvalue
(3) Form verification
- Built-in validator
A built-in validator needs to be introduced in the component class; when usingnew
keywords to createFormControl
objects, the second parameter is passed an array of validation rules
and isusername
defined asget
a type variable for easy access.
import {
FormGroup, FormControl,Validators} from "@angular/forms";
public carForm: FormGroup = new FormGroup({
username: new FormControl('', [
Validators.required,
Validators.minLength(4)])
})
get username() {
return this.carForm.get('username') as FormControl;
}
In the component template, you can use username
several properties to determine whether these validation rules have passed; you can carForm.valid
determine whether all the validation rules in the form have passed.
<form [formGroup]="carForm" (submit)="onSubmit()">
<input type="text" formControlName="username">
<div *ngIf="username.touched && username.invalid && username.errors">
<div *ngIf="username.errors['required']">Username is required</div>
<div *ngIf="username.errors['minlength']">Username must be at least 3 characters long</div>
</div>
<button type="submit" [disabled]="carForm.invalid">Submit</button>
</form>
(4) Custom form validator
Custom validators have the following rules:
- A custom validator is a
TypeScript
class - The class contains specific verification methods. The verification method must be static and
static
modified. - The verification method accepts a parameter
control
of type ,AbstractControl
which isFormControl
the type of the instance object of the class. - If the verification is successful, return
null
- If the verification fails, an object is returned, which
key
is the verification ID , indicating that the verification failed.value
true
(1) Customized synchronization form validator
1. Define synchronization validator
- The validator is a
ts
class, so it must be defined in a .ts file. - The parameter type received is
AbstractControl
- The returned parameter type is
ValidationErrors | null
- Method names and identification names should be consistent
- This class needs to be introduced by the component, so it needs to be
export
exported
import {
AbstractControl, ValidationErrors} from "@angular/forms";
export class MyValidators {
static connotContainSpace(
control: AbstractControl
): ValidationErrors | null {
if (/\s/.test(control.value)) {
return {
connotContainSpace: true}
}
return null;
}
}
2. Use sync validators
- Introduce custom validator in component class
import {
MyValidators} from "./MyValidators";
- When the form item is new, pass in the validation rules that need to be used by the form item. Write the definition directly without calling it.
public carForm: FormGroup = new FormGroup({
username: new FormControl('', [
Validators.required,
Validators.minLength(4),
MyValidators.connotContainSpace])
})
- Prompt in component template
<div *ngIf="username.touched && username.invalid && username.errors">
<div *ngIf="username.errors['required']">Username is required</div>
<div *ngIf="username.errors['minlength']">Username must be at least 3 characters long</div>
<div *ngIf="username.errors['connotContainSpace']">用户名不能包含空格</div>
</div>
(2) Custom asynchronous form validator
1. Define an asynchronous validator
- The type of the asynchronous validator return value is
Promise
orObservable
, and the result of thisPromise
resolve isValidators | null
- Asynchronous verification will only be performed after all synchronous verifications pass. If synchronous verification fails, asynchronous verification will not be performed.
// 异步验证器
static shouldBeUnique(
control: AbstractControl
): Promise<ValidationErrors | null> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (control.value === 'mosh') {
resolve({
shouldBeUnique: true})
} else {
resolve(null)
}
}, 2000)
})
}
2. Use asynchronous validators
- The asynchronous validator should be placed in
formControl
the third parameter when the object is created. - Used in templates the same as built-in validators
public carForm: FormGroup = new FormGroup({
username: new FormControl('', [
Validators.required,
Validators.minLength(5),
MyValidators.connotContainSpace],
MyValidators.shouldBeUnique)
})
3. Show verification status
formControl
The object has an attributepending
. During the execution of asynchronous verification, the attribute istrue
, otherwise it isfalse
<div *ngIf="username.pending">正在验证...</div>
(5) FormBuilder
FormBuilder
It is a class. Instance objects of this class can help us quickly create forms.FormGroup
You can use the method to create an objectformBuilder.group()
. This method receives two parameters. The first parameter iscontrols
the object composed of the form items. The second parameter is the verification ruleoptions
forformGroup
the object. The verification rules written here are usually self- Define validation rules and receive themformGroup
as parameters. You can define validation rules for all form items in the entire form. For example, two form items cannot be the same, etc.FormControl
You can use the method to createformBuilder.control()
an object. This method can accept three parameters. The first parameter is the default value of the form item. The second parameter is an array of synchronous form validators. The third parameter is an array of asynchronous form validators.- When creating
FormControl
an object, you can also directly use an array as a form itemvalue
. The array element list is the same asformBuilder.control()
the parameter list of the above method.
constructor(private formBuilder: FormBuilder) {
}
public form:FormGroup = this.formBuilder.group({
username: this.formBuilder.control(''),
password: ['', [Validators.required, Validators.minLength(6)]],
})
(6) Common methods of model-driven forms
(1)patchValue
- Set the value of the form control, you can set all, or you can set one
onPatchValue() {
this.form.patchValue({
username: 'mosh'
})
}
(2)setValue
- Set the values of all form controls. It won't work if you don't set it all.
onSetValue() {
this.form.setValue({
username: 'meggie',
password: '123456'
})
}
(3)valueChanges
- Event triggered when the value of a form control changes.
- You need to obtain a certain form control that you want to monitor changes, and then register the listening function
subscribe
The parameters obtained in the subscription function are the modified values
ngOnInit() {
this.form.get('username')?.valueChanges.subscribe(value => {
console.log(value);
})
}
(4)reset
- Leave form content blank
onReset() {
this.form.reset();
}