标签:str 视图 对象 rms 循环调用 class 函数 only foreach
使用 patchValue() 方法会比使用 setValue() 方法更好!
1、patchValue()
// angular2/packages/forms/src/model.ts export class FormGroup extends AbstractControl { ... patchValue( value: {[key: string]: any},{onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { Object.keys(value).forEach(name => { if (this.controls[name]) { this.controls[name].patchValue(value[name], {onlySelf: true, emitEvent}); } }); this.updateValueAndValidity({onlySelf, emitEvent}); } } // 使用示例 const form = new FormGroup({ first: new FormControl(), last: new FormControl() }); console.log(form.value); // {first: null, last: null} form.patchValue({first: ‘Nancy‘}); console.log(form.value); // {first: ‘Nancy‘, last: null}
从源码中我们可以看出,patchValue() 方法会获取输入参数对象的所有 key 值,然后循环调用内部控件的 patchValue()
方法,具体代码如下:
Object.keys(value).forEach(name => { if (this.controls[name]) { this.controls[name].patchValue(value[name], {onlySelf: true, emitEvent}); } });
首先,Object.keys()
会返回对象 key 值的数组,例如:
const man = {name : ‘Semlinker‘, age: 30}; Object.keys(man); // [‘name‘, ‘age‘]此外this.controls
包含了 FormGroup 对象中的所有 FormControl 控件,我们可以通过this.controls[name]
方式,访问到 name 对应的控件对象。
现在让我们来回顾一下创建 FormGroup 对象的相关代码
this.form = this.fb.group({ name: [‘‘, Validators.required], event: this.fb.group({ title: [‘‘, Validators.required], location: [‘‘, Validators.required] }) });
与之相对应的对象模型如下:
{ name: ‘‘, event: { title: ‘‘, location: ‘‘ } }
因此要更新该模型的值,我们可以利用 FormGroup
对象的 patchValue()
方法:
this.form.patchValue({ name: ‘Semlinker‘, event: { title: ‘Angular 4.x\‘s Road‘, location: ‘Xiamen‘ } });
以上代码将会通过循环的方式,更新每个 FormControl
控件。接下来我们看一下 FormControl
中 patchValue() 方法的具体实现:
patchValue(value: any, options: { onlySelf?: boolean, emitEvent?: boolean, emitModelToViewChange?: boolean, emitViewToModelChange?: boolean } = {}): void { this.setValue(value, options); }
patchValue()
方法有什么好处呢?假设我们使用 firebase
,那么当我们从 API 接口获取数据对象时,对象内部可能会包含 $exists
和 $key
属性。而当我们直接使用返回的数据对象作为参数,直接调用 patchValue() 方法时,不会抛出任何异常:this.form.patchValue({ $exists: function () {}, $key: ‘-KWihhw-f1kw-ULPG1ei‘, name: ‘Semlinker‘, event: { title: ‘Angular 4.x\‘s Road‘, location: ‘Xiamen‘ } });
其实没有抛出异常的原因,是因为在 patchValue() 内部循环时,我们有使用 if
语句进行条件判断。
2、setValue
setValue( value: {[key: string]: any}, {onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { this._checkAllValuesPresent(value); Object.keys(value).forEach(name => { this._throwIfControlMissing(name); this.controls[name].setValue(value[name], {onlySelf: true, emitEvent}); }); this.updateValueAndValidity({onlySelf, emitEvent}); } // 使用示例 const form = new FormGroup({ first: new FormControl(), last: new FormControl() }); console.log(form.value); // {first: null, last: null} form.setValue({first: ‘Nancy‘, last: ‘Drew‘}); console.log(form.value); // {first: ‘Nancy‘, last: ‘Drew‘}
Object.keys()
的循环,但在循环开始之前,我们会先调用 _checkAllValuesPresent()
方法,对输入值进行校验。 另外 _checkAllValuesPresent()
方法的具体实现如下:_checkAllValuesPresent(value: any): void { this._forEachChild((control: AbstractControl, name: string) => { if (value[name] === undefined) { throw new Error(`Must supply a value for form control with name: ‘${name}‘.`); } }); }
该方法内部通过 _forEachChild()
遍历内部的 FormControl 控件,来确保我们在调用 setValue()
方法时,设置的参数对象中,会包含所有控件的配置信息。如果 name
对应的配置信息不存在,则会抛出异常。
在 _checkAllValuesPresent()
验证通过后,Angular 会进入 Object.keys()
循环,此外在调用 setValue()
方法前,还会优先调用 _throwIfControlMissing()
判断控件是否存在,该方法的实现如下:
_throwIfControlMissing(name: string): void { if (!Object.keys(this.controls).length) { throw new Error(` There are no form controls registered with this group yet. If you‘re using ngModel, you may want to check next tick (e.g. use setTimeout). `); } if (!this.controls[name]) { throw new Error(`Cannot find form control with name: ${name}.`); } }
this.controls
是否存在,如果存在进一步判断 name
对应的 FormControl
控件是否存在。当 _throwIfControlMissing()
验证通过后,才会最终调用 FormControl
控件的 setValue() 方法:this.controls[name].setValue(value[name], {onlySelf: true, emitEvent})
我们来看一下 FormControl
类中,setValue() 方法的具体实现:
setValue(value: any, {onlySelf, emitEvent, emitModelToViewChange, emitViewToModelChange}: { onlySelf?: boolean, emitEvent?: boolean, emitModelToViewChange?: boolean, emitViewToModelChange?: boolean } = {}): void { this._value = value; if (this._onChange.length && emitModelToViewChange !== false) { this._onChange.forEach((changeFn) => changeFn(this._value, emitViewToModelChange !== false)); } this.updateValueAndValidity({onlySelf, emitEvent}); }
该方法的第一个参数,就是我们要设置的值,第二个参数是一个对象:
valueChanges
事件。默认值是 trueonChange
事件通知视图层。若未指定 emitModelToViewChange
的值,这是默认的行为。ngModelChange
事件将会被触发,用于更新模型。若未指定 emitViewToModelChange
的值,这是默认的行为。其实仅仅通过上面的代码,我们还是没完全搞清楚 setValue()
方法内部真正执行流程。如我们不知道如何注册 changeFn 函数和 updateValueAndValidity()
方法的内部处理逻辑,接下来我们先来看一下如何注册 changeFn 函数
export class FormControl extends AbstractControl { /** @internal */ _onChange: Function[] = []; ... /** * Register a listener for change events. */ registerOnChange(fn: Function): void { this._onChange.push(fn); } }
现在我们来回顾一下 setValue() 的相关知识点。对于 FormGroup
对象,我们可以通过 setValue()
方法更新表单的值,具体使用示例如下:
this.form.setValue({ name: ‘Semlinker‘, event: { title: ‘Angular 4.x\‘s Road‘, location: ‘Xiamen‘ } });
以上代码成功运行后,我们就能成功更新表单的值。但如果我们使用下面的方式,就会抛出异常:
this.form.setValue({ $exists: function () {}, $key: ‘-KWihhw-f1kw-ULPG1ei‘, name: ‘Semlinker‘, event: { title: ‘Angular 4.x\‘s Road‘, location: ‘Xiamen‘ } });
总结:patchValue 可以只更新副本的数据,而setValue则必须与form 数据结构一致才能进行更新。
angular 更新表单值的两种方法: setvalue,patchvalue
标签:str 视图 对象 rms 循环调用 class 函数 only foreach
原文地址:https://www.cnblogs.com/isylar/p/13163133.html