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

Angular CDK拖拽表单组时currentIndex始终为0的问题

Angular CDK表单组拖拽currentIndex始终为0的问题解决

已实现Angular CDK表单组内字段跨组拖拽,但拖拽整个表单组时,currentIndex始终显示为0,previousIndex正常,无法正确调整表单组顺序。

问题原因

  1. 外层表单组的cdkDropList未绑定[cdkDropListData],CDK无法关联到目标数组dummyFormData.fieldGroups,导致位置计算错误。
  2. 表单组内部嵌套了字段的cdkDropList,拖拽时CDK可能误识别触发元素,干扰外层容器的位置判断。
  3. dropNewGroup方法中直接调用dropGroup的逻辑有误,新增组后未正确处理拖拽事件索引。

解决方案

1. 修正外层cdkDropList配置

给外层表单组容器绑定[cdkDropListData],并给表单组的cdkDrag指定根元素,避免内部嵌套容器干扰:

<div cdkDropListGroup class="overall-container flex-row">
  <!-- 外层表单组拖拽容器:绑定数据源,指定垂直拖拽方向 -->
  <div class="flex-grow admin-grid-layout padding-right-regular" 
       cdkDropList 
       [cdkDropListData]="dummyFormData.fieldGroups"
       (cdkDropListDropped)="dropGroup($event)"
       cdkDropListOrientation="vertical">
    <!-- 表单组拖拽项:指定根元素为当前容器,避免内部cdkDropList触发拖拽 -->
    <div cdkDrag 
         cdkDragRootElement=".section-container"
         *ngFor="let group of dummyFormData.fieldGroups; let i = index" 
         class="entity-form-cell admin-form-column section-container">
      <app-admin-section-header [(title)]="group.header" (remove)="removeGroup(i)"></app-admin-section-header>
      <!-- 内部字段拖拽容器保持原有配置 -->
      <div cdkDropList [cdkDropListData]="group.fields" (cdkDropListDropped)="drop($event)" class="fields-group-list drop-list">
        <div *ngFor="let field of group.fields" class="admin-form-field flex-row align-center" cdkDrag cdkDragBoundary=".overall-container">
          <div class="dummy-form-field"></div>
        </div>
      </div>
    </div>
  </div>
  <!-- 新增组区域移到外层cdkDropList外部,避免干扰索引计算 -->
  <div class="entity-form-cell admin-form-column">
    <div cdkDropList (cdkDropListDropped)="dropNewGroup($event)" class="fields-group-list drop-list drop-area-hint">
      drop here to create new field group
    </div>
  </div>
  <!-- 右侧工具栏保持不变 -->
  <mat-card class="toolbar">
    <mat-card-content cdkDropList (cdkDropListDropped)="drop($event)" [cdkDropListData]="dummyFormData.availableFields" class="drop-list">
      <div class="drop-area-hint"></div>
    </mat-card-content>
  </mat-card>
</div>

2. 修正TypeScript方法逻辑

确保操作组件内的数据源,调整dropNewGroup的逻辑:

// 假设dummyFormData是组件类属性(避免全局变量)
dummyFormData = {
  fieldGroups: [
    { fields: ['photo'], header: "Personal Information" },
    { fields: ['name', 'projectNumber', 'admissionDate'], header: "Additional" },
    { fields: ['dateOfBirth', 'birth_certificate', 'gender', 'motherTongue'], header: "Additional" },
    { fields: ['center', 'status', 'address', 'phone'], header: "Scholar activities" }
  ],
  availableFields: ['field1', 'field2', 'field3'],
  createNewFieldPlaceholder: 'createNewFieldPlaceholder'
};

dropGroup(event: CdkDragDrop<any[]>) {
  moveItemInArray(
    this.dummyFormData.fieldGroups,
    event.previousIndex,
    event.currentIndex,
  );
}

dropNewGroup(event: CdkDragDrop<any>) {
  const newCol = { fields: [], header: "New Group" };
  this.dummyFormData.fieldGroups.push(newCol);
  // 若拖拽现有组到此处,调整其位置到数组末尾
  if (event.previousContainer.data === this.dummyFormData.fieldGroups) {
    moveItemInArray(
      this.dummyFormData.fieldGroups,
      event.previousIndex,
      this.dummyFormData.fieldGroups.length - 1
    );
  }
}

removeGroup(i: number) {
  this.dummyFormData.fieldGroups.splice(i, 1);
}

// 原有drop方法保持不变
drop(event: CdkDragDrop<any[]>) {
  // ... 你的原有逻辑
}

3. 关键注意点

  • cdkDropList必须绑定[cdkDropListData],CDK依赖该属性关联目标数组,才能正确计算拖拽索引。
  • 嵌套拖拽场景下,用cdkDragRootElement指定拖拽根元素,避免内部cdkDropList/cdkDrag干扰外层拖拽判断。
  • 新增组区域不要放在外层表单组的cdkDropList内部,否则会被算作容器内的一个项,导致索引计算混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 17:49:52