在Angular的信号表单中,将项从一个数组移动到另一个数组时出现的TypeError

前端开发 2026-07-08

我遇到了这个错误:

_effect-chunk2.mjs:2601 ERROR TypeError: s_r5 is not a function
    at Testing_For_24_Template (testing.ts:21:29)

在Angular v22的 signals形式中,将项从源数组移动到目标数组。我已经把代码简化成下面这个示例。

组件代码:

import { Component, signal } from '@angular/core';
import { form } from '@angular/forms/signals';

@Component({
  selector: 'app-testing',
  imports: [],
  templateUrl: './testing.html',
  styleUrl: './testing.css',
})
export class Testing {


  model = signal({
    source: new Array<string>(
      'test1',
      'test2',
      'test3'
    ),
    destination: new Array<string>()
  });

  testForm = form(this.model);

  on_select(event: Event, i: number) {
    const item = this.model().source[i];

    this.model().source.splice(i, 1);
    const new_source = this.model().source;

    this.model().destination.push(item);
    const new_dest = this.model().destination;

    this.model.set({ source: new_source, destination: new_dest });
  }
}

模板代码:

<p>testing works!</p>
<form>
<table>
  <caption>source</caption>
  <thead>
    <tr>
      <th>select</th>
      <th>text</th>
    </tr>
  </thead>
  <tbody>
    @for (s of testForm.source; let i = $index; track i) {
    <tr>
      <td>
        <button type="button" title="select" (click)="on_select($event, i)">select</button>
      </td>
      <td>{{ s().value() }}</td>
    </tr>
    }
  </tbody>
</table>
<table>
  <caption>destination</caption>
  <thead>
    <tr>
      <th>text</th>
    </tr>
  </thead>
  <tbody>
    @for (s of testForm.destination; let i = $index; track i) {
    <tr>
      <td>{{ s().value() }}</td>
    </tr>
    }
  </tbody>
</table>
</form>

它只是把项从源数组移动到目标数组,理论上应该更新显示,但却抛出了上面提到的错误。

解决方案

这可能是由于修改信号中使用的原始数组所致:

this.model().source.splice(i, 1);
const new_source = this.model().source;

[splice()] 方法会修改原始数组,而不是创建一个新数组。相反,应该使用 [toSpliced()] 方法:

const new_source = this.model().source.toSpliced(i, 1);

push() 方法也一样;它修改了已经被信号监听的原始数组。这会让UI状态变得混乱不堪。我认为 [concat()] 函数应该能解决问题,而不是 push()。完整代码如下:

  on_select(event: Event, i: number) {
    const item = this.model().source[i];
    const new_source = this.model().source.toSpliced(i, 1);
    const new_dest = this.model().destination.concat(item);

    this.model.set({ source: new_source, destination: new_dest });
  }
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章