Angular中的表单
- 表单控件
FormControl
:封装了表单的输入,并提供了一些可供操作的对象。 - 验证器
validator
:让我们能够以自己喜欢的任何方式验证表单的输入。 - 观察者
observer
:让我们能够监听表单的变化,并作出相应的回应。
FormControl
和FormGroup
Angular
中最基础的两个表单对象。FormControl
代表单一的输入字段,它是Angular
表单中的最小单元。FormControl
封装了这些字段的值和状态,比如是否有效,是否脏(被修改过),或是否有错误等。
let nameControl = new FormControl("Nate");
let name = nameControl.value; //Nate
FormGroup
可以为一组FormControl
提供总包接口(wrapper interface
),从而来管理多个FormControl
。- 当我们试图从
FormGroup
中获取value
时,会收到一个“键值对”结构的对象。它能让我们从表单中一次性获取全部的值而无需逐一遍历FormControl
。
let personInfo = new FromGroup({
firstName: new FormControl("Nate"),
lastName: new FormControl("Murray"),
zip: new FormControl("90210")
})
personInfo.value;
/*{
firstName : "Nate",
lastName: "Murray",
zip : "90210"
}
*/
Angular中两种使用表单的方式
FormsModule
为我们提供了一些模板驱动。(ngModel ngForm
)。ReactiveFormsModule
提供了下列指令(formControl ngFormGroup
)。
<div class="ui raised segment">
<h2 class="ui header">Demo Form : Sku</h2>
<form #f="ngForm"
(ngSubmit)="onSubmit(f.value)"
class="ui form">
<div class="field">
<label for="skuInput">SKU</label>
<input type="text"
id="skuInput"
placeholder="SKU"
name="sku" ngModel>
</div>
<button type="submit" ></button>
</div>
- 导入
FormsModule
之后,就可以在视图中使用NgForm
了,当这些指令在视图中可用时,它就会被附加到任何能匹配其selector
的节点上。 NgForm
做了一件便利但隐晦的工作:它的选择器包含form
标签(而不用显示添加ngForm
属性),这意味着当我们导入FormsModule
的时候,NgForm
就会被自动附加到视图中所有的<form>
标签上。NgForm
提供了两个重要的功能:- 一个名叫
ngForm
的FormGroup
对象。 - 一个输出事件(
ngSubmit
)。 #v=thing
语法的意思是:在当前视图中创建一个局部变量。这里我们为ngForm
创建了一个别名,并绑定到变量#f
上。
- 一个名叫
ngForm
是FormGroup
类型,这意味着我们可以把变量f
当作FormGroup
使用。而这也正是在输出事件(ngSubmit
)中的使用方法。- 如果
ngForm
是属性的键,那就是在告诉Angular
,我们要根据这个属性使用NgForm
指令。但在这里我们要对一个引用赋值,而把ngForm
用作属性值。这表示把ngForm
这个表达式的执行结果赋值给局部模板变量f
。 - 既然
ngForm
在这个节点上,那么这个f变量是FormGroup
类型,那么就可以在视图中的任何地方引用它。 - 即:当提交表单时,将会以表单的值作为参数,调用组件实例上的
onSubmit
方法。 NgModel
指令指定的是selector
是ngModel
,这意味着我们可以通过添加这个属性把它附加到input
标签上:ngModel="whatever"
,在这里我们指定了一个不带属性值的的ngModel
。- 有两种不同的方法能在模板中指定
ngModel
。 - 当使用不带属性值的
ngModel
时,我们要指定:- 单向数据绑定。
- 希望在表单中创建一个名为
sku
的FormControl
(这个sku
来自input
标签上的name
属性)。NgModel
会创建一个新的FormControl
对象,把它自动添加到父FormGroup
上。(这里也就是form
表单对象)。并把这个FormControl
对象绑定到一个DOM
上。即它会在视图中的input
标签和FormControl
对象之间建立关联。这种关联是通过name
属性建立的,本例中是sku
。
NgModel
与ngModel
区别:NgModel
是Pascal
命名法,指的是类和供代码中引用的对象。ngModel
是小写的驼峰命名法,来自指令的选择器selector
,并且只会被用在DOM
/模板上。
NgModel
和FormControl
并不是同一个,ngModel
是用在视图中的指令,FormControl
是用来表示表单中的数据和验证规则的。
FormBuilder
响应式表单
FormBuilder
是表单构建助手,表单是由FormControl
和FormGroup
构成的,而FormBuilder
则可以帮助我们创建它们。
import { FormBuilder, FormGroup} from '@angular/forms';
export class DemoFormSkuBuilder {
myForm: FormGroup;
constructor(fb: FormBuilder){
this.myForm = fb.group({
'sku' : ['ABC123']
})
}
onSubmit(value : string) : void{
console.log('you submitted value : ' , value);
}
}
-
Angular
将会注入一个从FormBuilder
类创建的对象实例,并把它赋给变量fb
。 -
将使用
FormBuilder
中两个主要的函数:control
,用于创建一个新的FormControl
group
,用于创建一个新的FormGroup
-
myForm
是FormGroup
类型,我们通过调用fb.group()
来创建FormGroup
,.group
方法的参数代表组件内各个FormControl
的键值对。 -
在视图中使用
myForm
<h2 class = "ui header">Demo Form: sku with Builder</h2>
<form [formGroup] ="myForm">
<div class = "field">
<label for="skuInput">SKU</label>
<input type="text" id="skuInput" placeholder="SKU" [formControl]="myForm.controls['sku']">
</div>
</form>
- 如果想要隐式的创建新的
FormGroup
和FormControl
,使用ngForm ngModel
。 - 如果要绑定一个现有的
FormGroup
和FormControl
,使用formGroup formControl
。
添加验证
- 验证器由
Validators
模块提供,Validators.required
是最简单的验证,表明指定的字段是必填项,否则就认为这个FormControl
是无效的。 - 使用验证器
- 为
FormControl
对象指定一个验证器。(可以直接把它作为第二个参数传给FormControl
的构造函数。) - 在视图中检查验证器的状态,并据此采取行动。
- 为
let control = new FormControl('sku', Validators.required);
constructor(fb: FormBuilder){
this.myForm = fb.group({
'sku' : ['', alidators.required]
})
}
在视图中使用验证
- 显式的把
sku
设置为实例变量。
export class DemoFormWithValidationsExplicit {
myForm: FormGroup;
sku : AbstracControl;
constructor(fb: FormBuilder){
this.myForm = fb.group({
'sku' : ['', alidators.required]
})
this.sku= this.myForm.controls['sku'];
}
onSubmit(value : string) : void{
console.log('you submitted value : ' , value);
}
}
- 验证整个表单的有效性
<div *ngIf = "!sku.valid" class="ui error message">
SKU is invalid
</div>
- 当
FormControl
无效时,为该字段显示一条错误信息
<div *ngIf = "!sku.valid" class="ui error message"> SKU is invalid</div> <div *ngIf = "sku.hasError('required') " class="ui error message"> SKU is required</div>
- 字段着色
<div class="field" [class.error]="!sku.valid && sku.touched"></div>
在这里为.error类设置了两个条件:检查!sku.valid
和sku.touched
,这是因为只有当用户修改过表单后(touched)才显示错误状态。
- 特定验证
<div *ngIf = "myForm.hasError('required', 'sku') " class="uerror"> SKU is required</div>
- 自定义验证器
function skuValidator(control : FormControl) : {s[: string]: boolean}{ if(!control.value.match(/^123/)){ return {invalidSku : true} }}
当输入值不是以123作为开始时,验证器会返回错误代码invalidSku
。
constructor( fb : FormBuilder){ this.myForm = fb.group({ 'sku':['' ,Validators.compose([ Valitators.required, skuValidator ])] })}
Validators.compose
把两个验证器包装在一起,我们可以将其赋值给FormControl
,只有两个验证都合法时,FormControl
才合法。
<div *ngIf="sku.hasError('invalidSku')" class="ui error message"> </div>
- 监听控件的变化
- 通过调用
control.valueChanges
访问到这个EventEmitter
。 - 然后,使用
.subscribe
方法添加一个监听器。
- 通过调用
constructor( fb : FormBuilder) { this.myForm = fb.group({ 'sku' : [' ', Validators.required] }); this.sku = this.myForm.controls['sku']; this.sku.valueChanges.subscribe( (value: string)=>{ console.log('sku changed to : ', value) } ); this.myForm.valueChanges.subscribe( (value: string)=>{ console.log('sku changed to : ', form) } );}
ngModel
双向绑定
export class DemoFormNgModel { myForm : FormGroup; productName: string; constructor( fb : FormBuilder){ this.myForm = fb.group({ 'productName': [' ', Validators.required] }); } onSubmit(value : string) : volid{ console.log(' you submitted value:' , value) }}
<label for="productNameInput">ProductName</label><input type="text" id="product name" [formControl]="myForm.get('productName') " [(ngModel)]="productName">
仍然用formControl
指定此input应该绑定到表单上的FormControl
,因为我们还需要对这个值加以进行验证并作为表单的一部分提交上去。