Angular CdkDropList拖拽后视图未更新问题求助
问题描述
我使用Angular的CdkDropList实现了两个列表的拖拽关联,拖拽元素后数组已正确更新,但视图中被拖拽元素未从原列表移除,还出现重复显示;再次拖拽原列表中看似相同的元素时,实际移动的是数组中当前第一个元素。
相关代码
HTML
<div cdkDropList #actionsList="cdkDropList" [cdkDropListData]="actionsWithoutManagement" [cdkDropListConnectedTo]="[managementActionsList]" (cdkDropListDropped)="drop($event)"> <div *ngFor="let item of filteredOptions" cdkDrag> <span>{{item.buttonValueTranslated }}</span> <span>{{item.buttonValue}}</span> </div> </div> <div cdkDropList #managementActionsList="cdkDropList" [cdkDropListData]="managementActions" [cdkDropListConnectedTo]="[actionList]" (cdkDropListDropped)="drop($event)"> <div *ngFor="let item of managementActions" cdkDrag> <span>{{ item.buttonValueTranslated }}</span> <span>{{ item.buttonValue }}</span> </div> </div>
Component.ts
import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { FormArray, FormBuilder, FormControl, FormGroup } from '@angular/forms'; import { CdkDragDrop, moveItemInArray,transferArrayItem,} from '@angular/cdk/drag-drop'; import { Observable, Subject, Subscription } from 'rxjs'; @Component({ selector: 'actions', templateUrl: './actions.component.html', styleUrls: ['./actions.component.scss'], }) export class ActionsComponent implements OnInit, OnDestroy { ... drop(event: CdkDragDrop<any[]>, from: string) { this.actionsInManagementForm?.clear(); console.log(this.actionsWithoutManagement) if (event.previousContainer === event.container) { moveItemInArray( event.container.data, event.previousIndex, event.currentIndex, ); } else { transferArrayItem( event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex, ); } }
问题原因
- 数据源与视图绑定不匹配:第一个列表的
cdkDropListData绑定的是actionsWithoutManagement,但*ngFor遍历的却是filteredOptions。拖拽时transferArrayItem修改的是actionsWithoutManagement,但视图渲染依赖的是filteredOptions,导致视图和实际数据源不同步,出现元素未移除、重复显示的问题。 - 模板引用变量错误:第二个列表的
cdkDropListConnectedTo写的是[actionList],但第一个列表的模板引用变量是#actionsList(多了一个s),这会导致拖拽关联逻辑异常,进一步影响视图更新的准确性。 - 变更检测未触发:如果
filteredOptions是基于actionsWithoutManagement衍生的过滤数组,但没有在数据源变化时重新计算或触发变更检测,也会导致视图无法同步更新。
修复方案
- 统一数据源绑定:将第一个列表的
*ngFor遍历对象改为actionsWithoutManagement,确保视图渲染和拖拽操作的数据源一致:
若<div *ngFor="let item of actionsWithoutManagement" cdkDrag> <span>{{item.buttonValueTranslated }}</span> <span>{{item.buttonValue}}</span> </div>filteredOptions是必须的过滤结果,需在actionsWithoutManagement变化时重新执行过滤逻辑,比如在drop方法末尾添加过滤代码。 - 修正模板引用变量:将第二个列表的
[cdkDropListConnectedTo]="[actionList]"修改为[cdkDropListConnectedTo]="[actionsList]",确保拖拽关联的是正确的列表容器。 - 确保变更检测触发:如果使用衍生数组,可通过
BehaviorSubject结合async管道实现自动更新,或在drop方法结束后注入ChangeDetectorRef并调用detectChanges()手动触发变更检测。
内容的提问来源于stack exchange,提问作者Marcos
相关产品推荐
相关产品推荐

