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
相关产品推荐
相关产品推荐

