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

Angular13如何避免移动后的数组项编辑值同步绑定到其他数组

Angular双列表穿梭框编辑值同步问题修复

问题现象

基于Angular13实现按钮控制的左右列表项移动功能时,将列表项从左侧移动到右侧后,在右侧列表编辑该项内容,编辑后的值会同步更新到左侧数组的对应项中。

问题原因

  • 移动列表项时直接将原对象推入目标数组,左右两个数组存储的是同一个JavaScript对象的内存引用,修改任意一侧的对象属性,另一侧指向同一内存地址的对象会同步变更
  • 原有移动逻辑存在错误:选中项推入目标数组后,又将同一项重新推回源数组,没有从源数组移除已移动的项,导致同一项同时存在于两个数组中
  • 模板中*ngFor绑定位置错误,绑定在<ul>标签上会生成多个无序列表,不符合列表结构规范

修复方案

修正TS侧移动逻辑

替换原有move方法,移动项时通过对象浅拷贝(简单对象场景适用,嵌套复杂对象可替换为structuredClone()等深拷贝方案)切断引用关联,同时正确从源数组移除已移动项,清空两侧选中状态:

public moveToTheRight(): void {
  this.move('agentInView', 'agentNotinView');
}

public moveToTheLeft(): void {
  this.move('agentNotinView', 'agentInView');
}

public move(from: string, to: string): void {
  // 筛选当前源列表中选中的待移动项
  const selectedItems = this[from].filter((item: any) => {
    return from === 'agentInView' 
      ? this.isInActiveGroupItems(item) 
      : this.isInActiveNotGroupItems(item);
  });

  // 拷贝待移动项加入目标数组,切断引用关联
  selectedItems.forEach(item => {
    this[to].push({...item});
  });

  // 从源数组移除已移动的项
  this[from] = this[from].filter((item: any) => {
    return from === 'agentInView' 
      ? !this.isInActiveGroupItems(item) 
      : !this.isInActiveNotGroupItems(item);
  });

  // 保留原有排序逻辑
  this[to].sort((a, b) => (a.id > b.id ? 1 : -1));

  // 清空所有选中状态
  this.activeItemsGroupView.length = 0;
  this.activeItemsNotInGroup.length = 0;
}

public toggleActiveInGroup(eventItem: any): void {
  if (this.activeItemsGroupView.find((item) => item === eventItem)) {
    this.activeItemsGroupView = this.activeItemsGroupView.filter(
      (item) => item !== eventItem
    );
  } else {
    this.activeItemsGroupView.push(eventItem);
  }
}
public toggleActiveNotInGroup(eventItem: any): void {
  if (this.activeItemsNotInGroup.find((item) => item === eventItem)) {
    this.activeItemsNotInGroup = this.activeItemsNotInGroup.filter(
      (item) => item !== eventItem
    );
  } else {
    this.activeItemsNotInGroup.push(eventItem);
  }
}

public isInActiveGroupItems(eventItem: any): boolean {
  return !!this.activeItemsGroupView.find((item) => item === eventItem);
}
public isInActiveNotGroupItems(eventItem: any): boolean {
  return !!this.activeItemsNotInGroup.find((item) => item === eventItem);
}

修正模板列表渲染逻辑

将*ngFor从<ul>标签移动到<li>标签上,避免生成多个冗余ul标签,修正后的列表结构如下:

<div class="card-body overflow-auto py-0">
  <!-- 左侧Group列表 -->
  <ul
    class="list-group list-group-flush"
    name="agentInGroup"
  >
    <li
      *ngFor="let child of agentInView"
      class="list-group-item {{
        isInActiveGroupItems(child) ? 'active' : ''
      }}"
      (click)="toggleActiveInGroup(child)"
    >
      {{ child.value }}
    </li>
  </ul>
</div>

<!-- 中间移动按钮部分保持原有代码不变 -->

<div class="card-body overflow-auto py-0">
  <!-- 右侧Not in Group列表 -->
  <ul
    class="list-group list-group-flush"
    name="agentNotInGroup"
  >
    <li
      *ngFor="let child of agentNotinView"
      class="list-group-item {{
        isInActiveNotGroupItems(child) ? 'active' : ''
      }}"
      (click)="toggleActiveNotInGroup(child)"
    >
      <input type="text" [(ngModel)]="child.value" />
    </li>
  </ul>
</div>

内容的提问来源于stack exchange,提问作者Bhrungarajni

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:27:16