79159156

Date: 2024-11-05 12:44:01
Score: 1
Natty:
Report link

try the below solution that allows both systems to work together harmoniously.

// grid.component.ts
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import { GridApi, ColumnApi, GridReadyEvent, DragStoppedEvent } from 'ag-grid-community';

interface Question {
  id: string;
  text: string;
  // add other question properties as needed
}

interface Section {
  id: string;
  name: string;
  questions: Question[];
}

@Component({
  selector: 'app-grid-component',
  template: `
    <div class="drop-zone" 
         [attr.data-section-id]="section.id"
         (dragenter)="onDragEnter($event)"
         (dragover)="onDragOver($event)"
         (dragleave)="onDragLeave($event)"
         (drop)="onExternalDrop($event)">
      <ag-grid-angular
        #agGrid
        class="ag-theme-pym w-100"
        domLayout="autoHeight"
        [rowData]="questions"
        [defaultColDef]="defaultColDef"
        [columnDefs]="columnDefs"
        [rowDragManaged]="true"
        [animateRows]="true"
        [suppressRowClickSelection]="true"
        [suppressCellFocus]="true"
        [suppressMovableColumns]="true"
        [getRowId]="getRowId"
        (gridReady)="onGridReady($event)"
        (rowDragEnter)="onRowDragEnter($event)"
        (rowDragEnd)="onRowDragEnd($event)"
        >
      </ag-grid-angular>
    </div>
  `,
  styles: [`
    .drop-zone {
      min-height: 50px;
      border: 2px dashed transparent;
      transition: border-color 0.2s ease;
    }
    
    .drop-zone.drag-over {
      border-color: #4CAF50;
    }
  `]
})
export class GridComponent implements OnInit {
  @Input() section!: Section;
  @Input() questions: Question[] = [];
  @Input() isPending = false;

  @Output() dragStart = new EventEmitter<void>();
  @Output() dragDrop = new EventEmitter<{sourceId: string, targetId: string}>();
  @Output() openEditQuestionModal = new EventEmitter<Question>();
  @Output() removeQuestion = new EventEmitter<Question>();

  private gridApi!: GridApi;
  private columnApi!: ColumnApi;
  private draggedQuestionId: string | null = null;

  columnDefs = [
    {
      field: 'text',
      headerName: 'Question',
      flex: 1,
      rowDrag: true
    },
    {
      field: 'actions',
      headerName: '',
      width: 100,
      cellRenderer: this.getActionsCellRenderer.bind(this)
    }
  ];

  defaultColDef = {
    sortable: false,
    suppressMovable: true
  };

  getRowId = (params: any) => {
    return params.data.id;
  };

  constructor() {}

  ngOnInit() {}

  onGridReady(params: GridReadyEvent) {
    this.gridApi = params.api;
    this.columnApi = params.columnApi;
  }

  // Handle AG-Grid row drag events
  onRowDragEnter(event: any) {
    const draggedNode = event.node;
    if (draggedNode) {
      this.draggedQuestionId = draggedNode.data.id;
    }
  }

  onRowDragEnd(event: DragStoppedEvent) {
    // Handle internal grid reordering
    if (event.overNode && event.node) {
      const sourceId = event.node.data.id;
      const targetId = event.overNode.data.id;
      this.dragDrop.emit({ sourceId, targetId });
    }
    this.draggedQuestionId = null;
  }

  // Handle external drag-drop events
  onDragEnter(event: DragEvent) {
    event.preventDefault();
    const dropZone = event.currentTarget as HTMLElement;
    dropZone.classList.add('drag-over');
  }

  onDragOver(event: DragEvent) {
    event.preventDefault();
    event.dataTransfer!.dropEffect = 'move';
  }

  onDragLeave(event: DragEvent) {
    event.preventDefault();
    const dropZone = event.currentTarget as HTMLElement;
    dropZone.classList.remove('drag-over');
  }

  onExternalDrop(event: DragEvent) {
    event.preventDefault();
    const dropZone = event.currentTarget as HTMLElement;
    dropZone.classList.remove('drag-over');

    // Handle drops from external sources (ngx-drag-drop)
    if (event.dataTransfer?.getData('text/plain')) {
      const sourceData = JSON.parse(event.dataTransfer.getData('text/plain'));
      this.dragDrop.emit({
        sourceId: sourceData.id,
        targetId: this.section.id
      });
    }
  }

  private getActionsCellRenderer(params: any) {
    const eDiv = document.createElement('div');
    eDiv.className = 'd-flex gap-2';

    const editButton = document.createElement('button');
    editButton.className = 'btn btn-sm btn-outline-primary';
    editButton.innerHTML = '<i class="fas fa-edit"></i>';
    editButton.addEventListener('click', () => this.openEditQuestionModal.emit(params.data));

    const deleteButton = document.createElement('button');
    deleteButton.className = 'btn btn-sm btn-outline-danger';
    deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
    deleteButton.addEventListener('click', () => this.removeQuestion.emit(params.data));

    eDiv.appendChild(editButton);
    eDiv.appendChild(deleteButton);
    return eDiv;
  }
}

// container.component.ts
import { Component, OnInit } from '@angular/core';
import { DndDropEvent } from 'ngx-drag-drop';

@Component({
  selector: 'app-container',
  template: `
    <div class="sections-container">
      <div class="section" *ngFor="let section of sections">
        <div class="section-header"
             [dndDraggable]="section"
             [dndEffectAllowed]="'move'"
             (dndStart)="onSectionDragStart($event)"
             (dndMoved)="onSectionMoved(section)">
          <h3>{{section.name}}</h3>
        </div>

        <div class="section-content" [ngbCollapse]="isCollapsed(section)">
          <app-grid-component
            [section]="section"
            [questions]="getQuestions(section)"
            [isPending]="editingAuditQuestions"
            (dragStart)="onQuestionDragStart($event)"
            (dragDrop)="onQuestionDragDrop($event)"
            (openEditQuestionModal)="onOpenEditQuestionModal($event)"
            (removeQuestion)="onRemoveQuestion($event)">
          </app-grid-component>
        </div>
      </div>
    </div>
  `
})
export class ContainerComponent implements OnInit {
  sections: Section[] = [];
  editingAuditQuestions = false;
  private draggedSection: Section | null = null;

  constructor() {}

  ngOnInit() {
    // Initialize your sections
  }

  onSectionDragStart(event: DragEvent) {
    this.draggedSection = event.source.data;
  }

  onSectionMoved(section: Section) {
    const sourceIndex = this.sections.indexOf(section);
    if (sourceIndex > -1) {
      this.sections.splice(sourceIndex, 1);
    }
  }

  onQuestionDragStart(section: Section) {
    // Handle question drag start
  }

  onQuestionDragDrop(event: { sourceId: string, targetId: string }) {
    // Handle question drop between sections or within the same section
    const sourceQuestion = this.findQuestion(event.sourceId);
    const targetSection = this.findSection(event.targetId);

    if (sourceQuestion && targetSection) {
      // Remove from source section
      const sourceSection = this.findQuestionSection(sourceQuestion);
      if (sourceSection) {
        sourceSection.questions = sourceSection.questions.filter(q => q.id !== sourceQuestion.id);
      }

      // Add to target section
      targetSection.questions.push(sourceQuestion);
    }
  }

  private findQuestion(id: string): Question | null {
    for (const section of this.sections) {
      const question = section.questions.find(q => q.id === id);
      if (question) return question;
    }
    return null;
  }

  private findSection(id: string): Section | null {
    return this.sections.find(s => s.id === id) || null;
  }

  private findQuestionSection(question: Question): Section | null {
    return this.sections.find(s => s.questions.some(q => q.id === question.id)) || null;
  }

  // Other methods...
}

I've try to solve that coordinates both AG-Grid's native drag-and-drop and ngx-drag-drop functionalities.

.ag-theme-pym .ag-row-drag {
  cursor: move;
}

.section-header {
  cursor: move;
  padding: 10px;
  background: #f5f5f5;
  margin-bottom: 10px;
}

.sections-container {
  display: flex;
  flex-direction: column;
  gap: 20px;
}
  1. Update your app.module.ts to include the required modules:
import { AgGridModule } from 'ag-grid-angular';
import { DndModule } from 'ngx-drag-drop';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';

@NgModule({
  imports: [
    AgGridModule,
    DndModule,
    NgbModule,
    // ... other imports
  ]
})
export class AppModule { }

This solution maintains both drag-and-drop systems while preventing conflicts between them. Would you like me to explain any specific part in more detail or help you with the implementation?

Reasons:
  • Long answer (-1):
  • Has code block (-0.5):
  • Ends in question mark (2):
  • Low reputation (0.5):
Posted by: Chintan