Angular 14中getRawValue()搭配indexOf无法正常工作的问题
Angular FormArray中getRawValue()与value的indexOf差异问题解析
问题重现
用户定义了结合Angular表单控件的Person类:
import { FormArray, FormControl, FormGroup } from '@angular/forms'; import { Address } from './address'; export class Person { id: FormControl<number>; name: FormControl<string>; addressList: FormArray<FormGroup<Address>>; }
在ngOnInit中完成表单初始化:
ngOnInit(): void { // initialize person this.person = this.fb.group<Person>({ id: new FormControl<number>(1, { nonNullable: true }), name: new FormControl<string>('Usama', { nonNullable: true }), // initialize addressList addressList: this.fb.array<FormGroup<Address>>([ this.fb.group<Address>({ id: new FormControl<number>(1, { nonNullable: true }), name: new FormControl<string>('Okara', { nonNullable: true }), }), this.fb.group<Address>({ id: new FormControl<number>(2, { nonNullable: true }), name: new FormControl<string>('Lahore', { nonNullable: true }), }), ]), }); this.filter(); }
在filter方法中出现异常:使用value调用indexOf能返回正确索引,但使用getRawValue()时返回-1:
filter() { let obj = this.person.controls.addressList.controls[0]; let add1 = this.person.controls.addressList.value.indexOf(obj.value); //works fine let add2 = this.person.getRawValue().addressList.indexOf(obj.getRawValue()); //does not works as expected console.log(add1); // returns 0 ---correct result console.log(add2); // returns -1 ---incorrect result }
问题原因
这是JavaScript对象引用比较机制导致的:
value和getRawValue()都会返回表单数据的字面量对象,但每次调用这两个方法时,Angular都会生成全新的对象实例。- 调用
obj.getRawValue()得到的是一个新对象,而this.person.getRawValue().addressList中的每一项也是全新生成的对象。虽然它们的属性值完全相同,但JavaScript中===(indexOf底层使用的比较方式)是按引用匹配的,不同引用的对象即使内容一致,也会被判定为不同元素,因此返回-1。 - 而
obj.value与this.person.controls.addressList.value[0]是同一个对象引用(addressList.value直接收集每个控件的value引用),所以indexOf能正确匹配到索引。
解决方案
要通过getRawValue()查找元素索引,不能依赖对象引用,而是要通过属性值进行匹配,使用findIndex方法替代indexOf:
方案1:匹配所有属性
filter() { let obj = this.person.controls.addressList.controls[0]; const targetRawValue = obj.getRawValue(); // 通过属性值匹配查找索引 let add2 = this.person.getRawValue().addressList.findIndex(item => item.id === targetRawValue.id && item.name === targetRawValue.name ); console.log(add2); // 返回0 ---正确结果 }
方案2:通过唯一标识匹配(推荐)
如果数据有唯一标识(比如id),可以只比较唯一属性,效率更高:
filter() { let obj = this.person.controls.addressList.controls[0]; const targetId = obj.getRawValue().id; let add2 = this.person.getRawValue().addressList.findIndex(item => item.id === targetId); console.log(add2); // 返回0 ---正确结果 }
内容的提问来源于stack exchange,提问作者Hammad Asif
相关产品推荐
相关产品推荐

