Angular响应式表单调用reset方法时plant对应FormControl值丢失问题
问题原因
出现该问题通常是以下几个常见原因导致:
传入的entity的plant属性不是自身可枚举属性
Angular的FormGroup.reset()方法在赋值时,只会遍历传入对象的自身可枚举属性,如果你的plant属性是定义在类的原型上、或者是不可枚举的访问器属性(getter),reset方法就无法读取到该属性,自然不会给对应的表单控件赋值。
比如你返回的entity如果是PlantArea类的实例,而plant属性是通过后续赋值到原型,或者构造函数里没有被正确标记为可枚举,就会触发这个问题。表单的plant控件被意外移除或禁用
如果在调用reset方法之前,代码其他位置执行了this.form.removeControl('plant')把该控件移除,或者调用了this.form.get('plant')?.disable()禁用了控件,那么form.value里默认就不会包含disabled的控件的值,你可以用form.getRawValue()打印所有控件的值(包含禁用的)确认是不是这个情况。控制台打印的引用对象存在懒加载特性
虽然你打印entity能看到plant属性,但是浏览器控制台打印引用对象时是懒加载的:你打印的时候展开看到的plant属性,是你点击展开时对象的最新值,不是执行console.log(entity)那一瞬间的值。你可以用console.log(JSON.stringify(entity))打印执行赋值瞬间的实体快照,确认当时plant属性确实存在且有值。
解决方案
你可以根据对应的原因选择解决方法:
- 如果是属性不可枚举的问题,先把实体转为普通对象再传入reset:
this.form.reset({...entity}); // 如果是嵌套对象可以用深拷贝处理: this.form.reset(JSON.parse(JSON.stringify(entity)));
- 如果是控件被禁用的问题,可以要么启用控件,要么读取值的时候用
getRawValue():
console.log(this.form.getRawValue());
- 也可以不用reset方法,改用patchValue方法赋值,兼容性更好:
this.form.patchValue(entity);
如果以上方法都无法解决,可以增加单独赋值逻辑做兜底:
this.form.reset(entity); if (entity?.plant) { this.form.get('plant')?.setValue(entity.plant); }
内容的提问来源于stack exchange,提问作者derstauner

