Angular表单valueChanges使用distinctUntilChanged对相同值不生效问题
问题原因分析
1. 核心底层原因是两者的默认行为共同导致的
- Angular响应式表单的valueChanges发射逻辑:调用
patchValue方法时,框架默认不会预先校验新值和旧值是否相等,只要未显式配置emitEvent: false,就会向valueChanges流发射最新的表单值。且每次发射的表单值是一个全新的普通对象实例,哪怕所有字段值和旧值完全一致,对象的引用地址也不同。 - RxJS
distinctUntilChanged的默认比较逻辑:该操作符默认使用===严格相等运算符对上游连续两次发射的值做比对。由于每次表单返回的是不同引用的对象,哪怕内部字段值完全相同,比对结果也会是false,操作符就不会拦截这次事件,表现为“失效”。
2. mat-select重复选中不触发事件的原因
Angular Material的mat-select组件内部默认做了值相等校验,当你选中的选项值和当前绑定的表单控件已存值相等(默认采用引用比对),就不会调用表单的setValue/patchValue方法,自然不会触发valueChanges事件,和你手动在countryChanged里加if判断的逻辑完全一致。
可选优化方案(无需修改触发逻辑)
可以给distinctUntilChanged传入自定义比较函数,实现深度值比对即可让操作符按预期工作:
// 方式1:使用深度比对方法 import { isEqual } from 'lodash-es'; this.form.valueChanges.pipe( distinctUntilChanged(isEqual) ).subscribe(data => { // 执行业务逻辑 }); // 方式2:自定义比对逻辑,仅校验需要的字段 this.form.valueChanges.pipe( distinctUntilChanged((prev, curr) => { // 示例只比对country字段,其他字段可按需补充 return prev.country === curr.country; }) ).subscribe(data => { // 执行业务逻辑 });
内容的提问来源于stack exchange,提问作者AlleXyS
相关产品推荐
相关产品推荐

