You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 05:10:32