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

如何实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 20:40:54