如何实现Angular CDK拖拽组件中数组与视图的同步?
问题:Angular CDK拖拽操作后数组数据未同步
使用Angular CDK拖拽功能实现任务在不同日期容器间移动时,界面能正常显示拖拽后的任务数量,但对应的数据数组并未更新。例如将周一的任务移到周二后,周二容器显示两个任务,但Tuesday数组的内容并未改变。
相关代码
周一容器HTML结构
<div class="example-container flex flex-col text-center h-fit min-h-[10rem] w-[15%] border-2 border-gray-100 rounded-md shadow-md" > <h2 class="text-xl font-semibold mx-auto py-4 bg-green-100 w-full drop-shadow-md" > Monday </h2> <div cdkDropList [cdkDropListData]="Monday" class="example-list bg-red-100 min-h-[5rem]" (cdkDropListDropped)="drop($event)" > @for (item of Monday; track item) { <app-drag-drop-item [title]="item" cdkDrag></app-drag-drop-item> } </div> </div>
周二容器HTML结构
<div class="example-container flex flex-col text-center h-fit min-h-[10rem] w-[15%] border-2 border-gray-100 rounded-md shadow-md" > <h2 class="text-xl font-semibold mx-auto py-4 bg-blue-100 w-full drop-shadow-md" > Tuesday </h2> <div cdkDropList [cdkDropListData]="Tuesday" class="example-list bg-red-100 min-h-[5rem]" (cdkDropListDropped)="drop($event)" > @for (item of Tuesday; track item) { <app-drag-drop-item [title]="item" cdkDrag></app-drag-drop-item> } </div> </div>
组件类代码(dashboard-space.component.ts)
import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CdkDragDrop, CdkDrag, CdkDropList, CdkDropListGroup, moveItemInArray, transferArrayItem, } from '@angular/cdk/drag-drop'; import { DragDropItemComponent } from '../drag-drop-item/drag-drop-item.component'; import { MatIconModule } from '@angular/material/icon'; import { FormsModule } from '@angular/forms'; import { AddTaskFormComponent } from '../add-task-form/add-task-form.component'; import { TaskService } from '../../../../shared/services/task.service'; @Component({ selector: 'app-dashboard-space', standalone: true, imports: [ CdkDropListGroup, CdkDropList, CdkDrag, DragDropItemComponent, DragDropItemComponent, // 重复导入的组件 MatIconModule, FormsModule, AddTaskFormComponent, CommonModule, ], templateUrl: './dashboard-space.component.html', styleUrl: './dashboard-space.component.css', }) export class DashboardSpaceComponent { constructor(private e: TaskService) { this.tasks = this.e.getTasks(); } tasks: any[]; todo = ['Get to work', 'Pick up groceries', 'Go home', 'Fall asleep']; Monday = ['Refractoring']; Tuesday = ['Gym']; Wednesday = ['Interview']; Thursday = ['TV']; Friday = ['Sport']; done = ['Get up', 'Brush teeth', 'Take a shower', 'Check e-mail', 'Walk dog']; newTask: string = ''; addNewTask() { this.todo.push(this.newTask); } handleFormSubmission(formData: any) { this.todo.push(formData); } drop(event: CdkDragDrop<string[]>) { 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, ); } } }
数组内容查看代码
<h1>{{ Monday }}</h1> <h1>{{ Tuesday }}</h1>
解决方案
1. 移除重复导入的组件
组件的imports数组中重复导入了DragDropItemComponent,可能导致组件实例异常,影响拖拽事件的正确处理。修改imports数组,删除重复项:
imports: [ CdkDropListGroup, CdkDropList, CdkDrag, DragDropItemComponent, // 仅保留一次导入 MatIconModule, FormsModule, AddTaskFormComponent, CommonModule, ],
2. 手动触发变更检测
如果组件因变更检测策略或其他原因未自动更新视图,可注入ChangeDetectorRef手动触发检测:
- 导入
ChangeDetectorRef:import { Component, ChangeDetectorRef } from '@angular/core'; - 构造函数注入:
constructor(private e: TaskService, private cdr: ChangeDetectorRef) { this.tasks = this.e.getTasks(); } - 修改
drop方法添加检测:drop(event: CdkDragDrop<string[]>) { 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, ); } // 手动触发变更检测 this.cdr.detectChanges(); }
3. 验证数组引用正确性
在drop方法中添加日志,确认操作的数组是组件的目标数组:
drop(event: CdkDragDrop<string[]>) { console.log('Previous container data:', event.previousContainer.data); console.log('Current container data:', event.container.data); 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, ); } }
查看控制台输出,确认打印的数组与组件的Monday/Tuesday等数组一致。若不一致,检查[cdkDropListData]绑定是否正确,确保绑定的是组件的数组属性而非副本。
4. 优化@for循环跟踪策略
当数组元素为字符串时,track item可能在元素重复时导致渲染异常,改为跟踪索引:
@for (item of Monday; track $index) { <app-drag-drop-item [title]="item" cdkDrag></app-drag-drop-item> }
内容的提问来源于stack exchange,提问作者suer231232131133
相关产品推荐
相关产品推荐

