Angular 表单快速入门
一、响应式表单
(一)创建一个输入框
对于响应式表单,需要先在组件类中定义表单模型,然后用 [formControl] 指令让它与视图中的表单元素联系起来。我们可以在 FormControl 实例定义时设置 value,也可以在之后使用 setValue 方法设置。当视图中的表单控件内容变化时,这个实例也会跟着变化。下面我们以一个输入框为例来看一下这两者之间的联系:
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
@Component({
selector: 'my-app',
template: `
<input type="text" placeholder="Username" [formControl]="username">
<pre>{{ username | json }}</pre>
`,
})
export class AppComponent {
username = new FormControl('');
constructor() {
this.username.setValue('jerry');
}
}
(二)添加验证规则
在响应式表单中,我们直接把验证器函数添加到表单控件模型上。一旦控件发生了变化,Angular 就会调用这些函数。当用户输入没有通过验证时,我们可以通过实例对象的 errors 属性来获取具体的有效性状态,同时输入框上的样式名会发生变化。我们以 required 和 maxLength 为例:
import { Component } from '@angular/core';
import { FormControl, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
template: `
<input type="text" placeholder="Username" [formControl]="username">
<span *ngIf="username.errors?.required">输入不能为空</span>
<span *ngIf="username.errors?.maxlength">最多10个字符</span>
`,
styles: [`
input { outline: none; }
input.ng-invalid { border-color: red; }
span { color: red; margin-left: 10px; }
`],
})
export class AppComponent {
username = new FormControl('', [Validators.required, Validators.maxLength(10)]);
}
(三)创建一个表单
响应式表单提供了 FormGroup 用于跟踪一组 FormControl 实例的值和有效性状态。FormGroup 的 key 就是每个子控件的名称,通过 [formControlName] 指令与视图中的表单元素关联。FormGroup 实例拥有和 FormControl 实例相同的属性和方法,当然这些属性和方法作用于这个表单组中的每个表单控件。下面我们来创建一个表单组:
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
template: `
<form [formGroup]="userInfo">
<input type="text" placeholder="Username" formControlName="username">
<div>
<span *ngIf="userInfo.controls.username.errors?.required">输入不能为空</span>
<span *ngIf="userInfo.controls.username.errors?.maxlength">最多10个字符</span>
</div>
<input type="password" placeholder="Password" formControlName="password">
<div>
<span *ngIf="userInfo.controls.password.errors?.required">输入不能为空</span>
<span *ngIf="userInfo.controls.password.errors?.pattern">请输入6位数字</span>
</div>
</form>
<pre>Form Value: {{ userInfo.value | json }}</pre>
<pre>Form Valid: {{ userInfo.valid }}</pre>
`,
styles: [`
form {
display: grid;
grid-template-columns: 175px auto;
grid-gap: 10px;
justify-items: stretch;
}
input { outline: none; }
input.ng-invalid { border-color: red; }
span { color: red; }
`]
})
export class AppComponent {
userInfo = new FormGroup({
username: new FormControl('', [Validators.required, Validators.maxLength(10)]),
password: new FormControl('', [Validators.required, Validators.pattern(/^[\d]{6}$/)]),
});
}
(四)对表单控件进行分组
表单组可以同时接受单个表单控件实例和其它表单组实例作为其子控件。简单地说就是 FormGroup 实例中可以嵌套 FormGroup 实例或者 FormArray 实例,形成嵌套的表单组。
import { Component } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
@Component({
selector: 'my-app',
template: `
<form [formGroup]="userInfo">
<div formGroupName="username" class="form-group">
<input type="text" placeholder="First Name" formControlName="first">
<div>
<span *ngIf="userInfo.controls?.username.controls.first.errors?.required">输入不能为空</span>
<span *ngIf="userInfo.controls?.username.controls.first.errors?.maxlength">最多10个字符</span>
</div>
<input type="text" placeholder="Last Name" formControlName="last">
<div>
<span *ngIf="userInfo.controls?.username.controls.last.errors?.required">输入不能为空</span>
<span *ngIf="userInfo.controls?.username.controls.last.errors?.maxlength">最多10个字符</span>
</div>
</div>
<input type="password" placeholder="Password" formControlName="password">
<div>
<span *ngIf="userInfo.controls.password.errors?.required">输入不能为空</span>
<span *ngIf="userInfo.controls.password.errors?.pattern">请输入6位数字</span>
</div>
</form>
<pre>Form Value: {{ userInfo.value | json }}</pre>
<pre>Form Valid: {{ userInfo.valid }}</pre>
`,
styles: [`
form, .form-group {
display: grid;
grid-template-columns: 175px auto;
grid-gap: 10px;
justify-items: stretch;
}
.form-group { grid-column: 1 / 3; }
input { outline: none; }
input.ng-invalid { border-color: red; }
span { color: red; }
`]
})
export class AppComponent {
userInfo = new FormGroup({
username: new FormGroup({
first: new FormControl('', [Validators.required, Validators.maxLength(10)]),
last: new FormControl('', [Validators.required, Validators.maxLength(10)]),
}),
password: new FormControl('', [Validators.required, Validators.pattern(/^[\d]{6}$/)]),
});
}
(五)使用 FormBuilder 服务生成控件
当我们需要创建多个表单控件实例时,代码会显得会比较臃肿。FormBuilder 提供了一个语法糖,以简化 FormControl、FormGroup 或 FormArray 实例的创建过程。下面我们用它来重构一下上面的表单创建:
export class AppComponent {
userInfo = this.fb.group({
username: this.fb.group({
first: ['', [Validators.required, Validators.maxLength(10)]],
last: ['', [Validators.required, Validators.maxLength(10)]],
}),
password: ['', [Validators.required, Validators.pattern(/^[\d]{6}$/)]],
});
constructor(private fb: FormBuilder) {}
}
二、模板驱动表单
(一)创建一个输入框
模板驱动表单和 AngularJS 中的表单相似,通过 NgModel 指令来实现双向绑定。
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<input type="text" placeholder="Username" [(ngModel)]="username">
<pre>{{ username }}</pre>
`,
})
export class AppComponent {
username = 'jerry';
}
(二)添加验证规则
在模板驱动表单中只能通过属性添加验证规则,就像原生的 HTML 表单验证器。我们需要先把 ngModel 导出成局部模板变量才能查看该控件的状态。 比如下面这个例子:
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<input type="text" placeholder="Username" [(ngModel)]="username" required #usernameCtrl="ngModel">
<span *ngIf="usernameCtrl.errors?.required">输入不能为空</span>
`,
styles: [`
input { outline: none; }
input.ng-invalid { border-color: red; }
span { color: red; margin-left: 10px; }
`],
})
export class AppComponent {
username = '';
}
(三)创建一个表单
在使用 form 标签后,其中通过 NgModel 指令双向绑定的表单控件必须添加 name 属性。同 ngModel,我们可以通过把 ngForm 导出成局部模板变量来查看表单的状态。
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `
<form #userInfo="ngForm">
<input type="text" placeholder="Username" [(ngModel)]="username" required maxlength="10" name="username">
<div>
<span *ngIf="userInfo.controls.username?.errors?.required">输入不能为空</span>
</div>
<input type="password" placeholder="Password" [(ngModel)]="password" required pattern="^[\\d]{6}$" name="password">
<div>
<span *ngIf="userInfo.controls.password?.errors?.required">输入不能为空</span>
<span *ngIf="userInfo.controls.password?.errors?.pattern">请输入6位数字</span>
</div>
</form>
<pre>Form Value: {{ userInfo.value | json }}</pre>
<pre>Form Valid: {{ userInfo.valid }}</pre>
`,
styles: [`
form {
display: grid;
grid-template-columns: 175px auto;
grid-gap: 10px;
justify-items: stretch;
}
input { outline: none; }
input.ng-invalid { border-color: red; }
span { color: red; }
`],
})
export class AppComponent {
username = '';
password = '';
}
(四)对表单控件进行分组
在模板驱动表单中对表单控件进行分组需要使用 NgModelGroup 指令。该指令只能用作 NgForm 的子级(在