在新版本的 Angular 中并没双向绑定的功能,而在表单中所谓的双向绑定则是通过属性绑定和事件绑定来完成的。
目前来说,表单的操作的两种形式:FormsModule
和ReactiveFormsModule
。这两种形式分别作用于:模板式表单和动态构建式的表单。
FormsModule
和ReactiveFormsModule
分别提供了一系列不同的指令集合。
使用表单操作时,必须引入以上的模板,否则会直接报错。
FormControl
FormControl 是 Form 表单中的一部分且不可见,通常用在一些比较简单的元素上,如文本框。
const c = new FormControl(value,Validators)
第一个参数表示表单的初始值,第二个参数表示表单的验证器,如:Validators.required
FormControl 在开发中常用到的属性有:value, status, errors
- value: 表单当前值
- status: 表单当前状态,无效还是有效
- errors:表单当前错误集合(表单的验证器可以设置多个)
FormGroup
FormGroup 是一个固定FormControl表单元素的集合
const c = new FormGroup({
name:new FormControl('lisi',Validators.required),
addr:new FormControl('shenzhen',[Validators.required,...])
})
const c = new FormControl({
name:new FormControl('lishi'),
contract:new FormGroup({
mobile:new FormControl('10086'),
wechat:new FormGroup('wechat')
}),
langular:new FormArray([
new FormControl('Javascript'),
new FormControl('Angular'),
new FormControl('Vue')
]),
remark:new FormControl('--')
})
...
FormGroup 用于管理一级不同控件类型的集合,可用于构建ReactiveFormsModule的表单时动态创建表单对象,与FormControl一样有着同样的验证功能。
FormGroup下的任意一个FormControl的数据发生的变化,FormGroup的数据也会同时发生变化。但FormGroup的状态和errors有点不一样,FormGroup下所有FormControl的errors都是独立的,且每个FormControl都有自己的errors 集合。
FormGroup状态的验证规则,如下:
- 任一FormControl 的状态是无效的,则认定FormGroup的状态验证是无效的
- 若所有的FormControl的状态被验证是有效的,但 FormGroup有错误发生则也认定为FormGroup状态为无效的
- 若所有的FormControl的状态被验证是有效的,且 FormGroup没有错误提示则认定FormGroup的表单状态有效
通过以上这几条规则可以看出,FormGroup 很适合用在动态创建表单的场景(动态添加输入框,动态添加按钮...)
FormArray
FormArray 用于管理一组具有相同控件类型的集合
const c = new FormArray([
new FormControl('name',Validators.required),
new FormControl('addr',Validators.required),
...
])
与FormControl、FormGroup一样,FormArray同样具有 value、status、errors 。
更新 Form Model
更新 Form Model
的方式:setValue
, patchValue
- setValue 更新所有数据,使用strict模式同时要求value完全匹配Form的结构才会更新数据不然会报错
- patchValue 更新当前控件数据,使用标准模式,不要求value完全匹配Form结构也会更新数据且不报错
从上面这两条规则可以知道:
setValue 用于更新一组值
patchValue 用于更新某个值
验证器(Validators)
Form表单中所谓的验证器其实就是一组普通函数操作的集合
class Validators {
static required(control):{[key:string]:any}{
return isEmptyValue(control.value) ? {'required':true} : null;
}
static minLen(min:number):ValidatorFn {
return (control):{[key:string]:any} => {
const len:number = control.value ? control.value.length : 0;
return len < min ? {'requireLen':min,'actualLength':len} : null;
}
}
}
组件验证器Validators(合并多个为一个):
const ValidatorFn = Validators.compose([
Validators.minLen(10),
Validators.required,
Validators.maxLen(20)
])
const email = new FormControl('demo@qq.com',ValidatorFn);
监听数据变化
时时响应控件数据的变化:
const c = new FormControl({
name:new FormControl('lishi'),
contract:new FormGroup({
mobile:new FormControl('10086'),
wechat:new FormGroup('wechat')
}),
langular:new FormArray([
new FormControl('Javascript'),
new FormControl('Angular'),
new FormControl('Vue')
]),
remark:new FormControl('--')
})
c.valueChanges.subscribe(r=>console.log('changed',r))
c.statusChanges.subscribe(r=>console.log('changed',r))
FormGroup 在模板中的使用
在Form表单中的使用
<form [formGroup]="loginForm">
<input type='text' formControlName='uname' />
<input type='text' formControlName='upwd' />
<p>{{loginForm.get('uname').value}}</p>
<p>{{loginForm.get('upwd').value}}</p>
<p>{{loginForm.value | json}}</p>
</form>
ReactiveForms 表单使用的几个条件
ReactiveForms 的成功使用需要以下几个条件:
- 必须实现FormGroup 和 formControlName 这两个指令,否则不好意思直接报错
- 必须手动构建Form Model
- 绑定Form Model 与对象的dom结构中,如
formControlName
,formGroup
- formControlName的值必须与formGroup对应的key值对应
实现自定义控件
ControlValueAccessor
功能类似于一个连接到ngModel的适配器(adapter),常用于构建自定义的元素类型或Angular组件中,如:
@Component({
selector: 'form-text',
template: `
<div >
<label>{{label}}:</label>
<input type="text" [(ngModel)]="value"
placeholder="{{placeholder}}" >
</div>
`,
providers: [
{
provide:NG_VALUE_ACCESSOR,
useExisting:forwardRef(()=>FormTextComponent),
multi:true
}
]
})
export class FormTextComponent implements ControlValueAccessor {
@Output() onChange: EventEmitter<any> = new EventEmitter<any>();
public label:string = '用户名';
public placeholder='请输入用户名';
public innerValue: any;
public changeFn: Function = () => {};
get value(): any {
return this.innerValue;
};
set value(v: any) {
if (v !== this.innerValue) {
this.innerValue = v;
this.changeFn(v);
}
}
writeValue(value: any) {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
registerOnChange(fn: any) {
this.changeFn = fn;
}
registerOnTouched(fn: any) {
//
}
}
2018.5.9 天之骄子 深圳
来源:https://segmentfault.com/a/1190000014801031?utm_source=index-hottest
如果给你带来帮助,欢迎微信或支付宝扫一扫,赞一下。