0

I have a list of items and I need to drag and drop each of the item to a droppable container. I am using copyArrayItem from @angular/cdk/drag-drop. Also, I want to update some properties of each item after droping it to the droppable container.

The problem I'm facing is, if I drag and drop 'Item-1' two times to the droppable container and if I update the properties of one among it, then it results in the update of both item's properties.

How can I fix this, or how can I update a unique item after dropping it to the droppable container?

component.html

    <div>
    <div class="jfs-container">
        <div class="jfs-actions">
            <button mat-raised-button class="btn-clear" (click)="clearForm()">
                <mat-icon>clear</mat-icon>
            </button>
            <button mat-raised-button class="btn-generate" (click)="generateForm()">Save</button>
        </div>
        <div class="jfs-wrapper">
            <div class="jfs-builder">
                <div class="jfs-controls" cdkDropList #controlList="cdkDropList" [cdkDropListData]="controls"
                    cdkDropListSortingDisabled [cdkDropListConnectedTo]="[previewList]"
                    (cdkDropListDropped)="dropControl($event)" (cdkDropListExited)="dropListExited($event)"
                    (cdkDropListEntered)="dropListEntered()">
                    <div class="jfs-display" *ngFor="let control of controls" cdkDrag [cdkDragData]="control">
                        <div class="jfs-display" *cdkDragPlaceholder>
                            <a> {{ control.displayName }} </a>
                        </div>
                        <a> {{ control.displayName }} </a>
                    </div>
                </div>
            </div>
            <div class="jfs-previewer">
                <div class="jfs-dropper" cdkDropList #previewList="cdkDropList" [cdkDropListData]="generatedControls"
                    (cdkDropListDropped)="dropControl($event)">
                    <span *ngIf="generatedControls.length === 0" class="jfs-drag-info">Drag and drop an item</span>
                    <div class="jfs-component" *ngFor="let control of generatedControls; let controlIndex=index;"
                        cdkDrag>
                        <ng-container [ngSwitch]="control.type">
                            <div class="jfs-btn-group">
                                <mat-icon (click)="deleteComponent(control, controlIndex)" class="delete">delete_forever
                                </mat-icon>
                                <mat-icon (click)="openDetailsEditorDialog(control, controlIndex)" class="edit">edit
                                </mat-icon>
                            </div>
                            <div *ngSwitchCase="'itemOne'">
                                Item One
                            </div>
                            <div *ngSwitchCase="'itemTwo'">
                                Item Two
                            </div>
                        </ng-container>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <code>{{ UIDisplay }}</code>
</div>

component.ts

 import { copyArrayItem, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ControlType } from '../interface/control-type';
import { ControlEditorModalComponent } from '../modal/control-editor-modal/control-editor-modal.component';
import { Controls } from '../utils/controls/controls';

@Component({
  selector: 'app-form-structurizer',
  templateUrl: './form-structurizer.component.html',
  styleUrls: ['./form-structurizer.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class FormStructurizerComponent implements OnInit {

  public controls: Array<ControlType> = Controls;
  public generatedControls: Array<ControlType> = [];
  public UIDisplay: any;

  constructor(
    private dialog: MatDialog
  ) { }

  ngOnInit(): void {
  }

  dropControl(event: any): void {
    if (event.previousContainer !== event.container) {
      copyArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
      this.openDetailsEditorDialog(event);
    } else {
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    }
    if (event.previousContainer.data) {
      this.controls = this.controls.filter((control) => !control.droppedFlag);
    }
  }

  dropListExited(event: any): void {
    const currentIndex = event.container.data.findIndex(
      (control: ControlType) => control.type === event.item.data.type
    );
    this.controls.splice(currentIndex + 1, 0, {
      ...event.item.data,
      droppedFlag: true,
    });
  }

  dropListEntered(): void {
    this.controls = this.controls.filter((control) => !control.droppedFlag);
  }

  openDetailsEditorDialog(event: any, index?: number): void {
    let control: ControlType = { displayName: '', type: '' };

    if (event?.container) {
      control = event?.container?.data[event?.currentIndex];
      index = event?.currentIndex;
    } else if (event?.displayName) {
      control = event;
    }

    this.dialog.open(ControlEditorModalComponent, {
      width: '900px',
      disableClose: true,
      panelClass: 'control-editor-modal',
      data: {
        control: control
      },
    }).afterClosed().subscribe((result: any) => {
      if (result && index !== undefined)
        this.update(result, index);
    });
  }

  update(jsonComponent: any, index: number): void {
    if (jsonComponent && index !== undefined) {
      this.generatedControls[index].struct = JSON.parse(jsonComponent);
    }
  }

  deleteComponent(control: ControlType, index: number): void {
    this.generatedControls.splice(index, 1);
  }

  clearForm(): void {
    this.generatedControls = [];
  }

  generateForm(): void {
    let formGenerated: any = { "components": [] }

    this.generatedControls.forEach((control: ControlType) => {
      if (control.struct) {
        formGenerated.components.push(control.struct);
      }
    });

    this.UIDisplay = formGenerated;
  }
}

Please find the image of the sample project.

Akhil Joseph
  • 1
  • 1
  • 3
  • You need to include some code with this, otherwise it's hard for anyone to guess what might be the problem. I guess it's the fact that you always push the same instance of item1 to the array with dropped items. Try to `push({...item})` instead. – Octavian Mărculescu Oct 20 '22 at 06:36
  • @OctavianMărculescu thanks for the comment and I've added the code in the post. – Akhil Joseph Oct 20 '22 at 09:13

0 Answers0