Angular ng2-dragula动态TD中添加学科的拖拽实现问题
Hey there! I’ve tackled similar dynamic table drag-and-drop tasks with ng2-dragula before, so let’s break down how to make your subject-filled TDs work perfectly with your classHours data.
Step 1: Set Up Dragula Service & Initial Data
First, make sure you’ve got the Dragula service injected and your base data ready. We’ll need a parallel array to track subjects for each time slot, since your classHours holds time data, not subject info.
import { Component } from '@angular/core'; import { DragulaService } from 'ng2-dragula'; @Component({ selector: 'app-schedule', templateUrl: './schedule.component.html', styleUrls: ['./schedule.component.css'] }) export class ScheduleComponent { // Your classHours data (trimmed for brevity) classHours = [ { "cd_horario_das_aulas": "1", "hr_inicial": "08:00:00", "hr_final": "09:00:00" }, { "cd_horario_das_aulas": "2", "hr_inicial": "10:00:00", "hr_final": "11:00:00" }, { "cd_horario_das_aulas": "3", "hr_inicial": "13:00:00", "hr_final": "14:00:00" } ]; // Parallel array to store subjects for each time slot subjects: string[] = new Array(this.classHours.length).fill(''); constructor(private dragulaService: DragulaService) { // Create a dragula group to manage our TDs this.dragulaService.createGroup('scheduleGroup', { moves: () => true, // Allow all TDs in the group to be dragged copy: false, // Move items instead of copying revertOnSpill: true // Return item to original spot if dropped outside the container }); // Listen for drop events to sync subject data with the new order this.dragulaService.drop('scheduleGroup').subscribe(({ el, source, target }) => { const oldIndex = Array.from(source.children).indexOf(el); const newIndex = Array.from(target.children).indexOf(el); // Update the subjects array to match the new TD order if (oldIndex !== newIndex) { const movedSubject = this.subjects.splice(oldIndex, 1)[0]; this.subjects.splice(newIndex, 0, movedSubject); } }); } }
Step 2: Dynamically Render TDs with Drag Support
In your template, use *ngFor to loop through classHours, and attach the dragula directive to each TD. Bind the subject data so it updates as items are dragged.
<table class="schedule-table"> <thead> <tr> <th>学科</th> <th>时间段</th> </tr> </thead> <tbody> <tr *ngFor="let hour of classHours; let i = index"> <!-- Drag-enabled TD bound to the corresponding subject --> <td [dragula]='"scheduleGroup"' class="drag-handle"> {{ subjects[i] || '点击添加学科' }} <!-- Optional: Add an input to edit the subject --> <input *ngIf="!subjects[i]" type="text" [(ngModel)]="subjects[i]" placeholder="输入学科名称"> </td> <td>{{ hour.hr_inicial.slice(0,5) }} - {{ hour.hr_final.slice(0,5) }}</td> </tr> </tbody> </table>
Step 3: Add Custom Drag Styles (Optional)
Make the drag experience clearer with some custom CSS. Dragula adds default classes like gu-transit (dragging item) and gu-mirror (ghost element) you can style:
.drag-handle { cursor: grab; padding: 8px; border: 1px solid #eee; } .drag-handle:active { cursor: grabbing; } .gu-transit { opacity: 0.5; background-color: #f5f5f5; } .gu-mirror { border: 2px solid #2196F3; background-color: white; box-shadow: 0 2px 8px rgba(0,0,0,0.15); }
Key Notes to Avoid Issues
- Data Sync: The
dropevent listener ensures yoursubjectsarray always matches the visual order of TDs—critical for keeping your data consistent. - Dynamic Elements: Since we’re using
*ngFor, dragula will automatically pick up new TDs if you add more items toclassHourslater (just make sure to push a blank value tosubjectstoo). - Input Integration: The optional input lets users add subjects directly in the TD—you can expand this to use a modal or dropdown if needed.
内容的提问来源于stack exchange,提问作者Herick

