reppners / ngx-drag-drop

Angular directives using the native HTML Drag And Drop API
https://reppners.github.io/ngx-drag-drop/
BSD 3-Clause "New" or "Revised" License
299 stars 118 forks source link

flickering, 5th item exist a few ms onDrop() (with 4 items in list) #31

Closed robvaneck closed 2 years ago

robvaneck commented 5 years ago

Hi,

I have 4 items in a ngFor loop, which are draggable.. I follow the code from the example docs.. The callback functions update my model..

but now i see a flickering, a few miliseconds.. a 5th item has been added, and then is removed.

Can we solve this?

import { Component, OnInit, Input, OnChanges } from '@angular/core';
import { AbstractControl } from '../../../../node_modules/@angular/forms';
import { Question } from '../../_types/models/question';
import { QuestionDataSource } from '../../_types/models/questionDatasource';

import * as _ from 'lodash';
import { QuestionOption } from '../../_types/models/questionOption';

@Component({
  selector: 'custom-sortable-sequence',
  templateUrl: './custom-sortable-sequence.component.html'
})
export class CustomSortableSequenceComponent implements OnChanges {

  @Input() control: AbstractControl;
  @Input() question: Question;
  @Input() dataSource: QuestionDataSource;

  ngOnChanges(): void {
    this.updateValue();
  }

  // adds the dropped option to our datasource
  onDrop(e: any): void {
    let index = e.index;

    if (typeof index === 'undefined') {
      index = this.dataSource.options.length;
    }

    this.dataSource.options.splice(index, 0, e.data);
  }

  // removes the dropped option from it's old position
  onDragged(option: QuestionOption): void {
    const index = this.dataSource.options.indexOf(option);
    this.dataSource.options.splice(index, 1);
    this.updateValue();
  }

  // update the form control value
  updateValue(): void {
    const formValue = [];
    this.dataSource.options.forEach(option => {
      formValue.push(option.value);
    });

    this.control.setValue(formValue);
  }
}
robvaneck commented 5 years ago

atm i solve this using:

  // first: tells us the dropped object and new index
  onDrop(e: any): void {
    let index = e.index;

    if (typeof index === 'undefined') {
      index = this.dataSource.options.length;
    }

    this.insertAtIndex = index;
    this.insertOption = e.data;
  }

  // second: adds the new object
  // and removes the dropped option from it's old position
  onDragged(option: QuestionOption): void {
    this.dataSource.options.splice(this.insertAtIndex, 0, this.insertOption);
    const index = this.dataSource.options.indexOf(option);
    this.dataSource.options.splice(index, 1);
    this.updateValue();
  }
reppners commented 5 years ago

I was able to reproduce with this stackblitz: https://stackblitz.com/edit/ngx-drag-drop-issue-31?file=src%2Fapp%2Fapp.component.ts

See the onDragged() function where I put in a kind of sleep function to simulate a function call taking 1s and also conditionally invoke it to demonstrate blocking or deferring the blocking call to the next event loop by putting it into a setTimeout.

I'm not sure if this can and should be fixed in the library or if this is up to the library user to either optimize functions called in the drag/drop handlers or defer it to the next event loop if optimization is not possible.

EDIT: Totally forgot to say Welcome and thanks for reporting! I've startet a new job which takes much of my mental energy and I have to be very "efficient" with the time I put into maintaining OSS projects so please forgive me when answering can take up to one week.

reppners commented 2 years ago

Closing this for now, if needed we can reopen and discuss possible solutions on the library level.