angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.38k stars 6.76k forks source link

Drag and drop does not work correctly when data is changed while dragging #15343

Open volser opened 5 years ago

volser commented 5 years ago

What is the expected behavior?

When change data while dragging, for example when have lazy load of items. D&d should update siblings and draggables

What is the current behavior?

current just ignore, cuz copy data before drag https://github.com/angular/material2/blob/master/src/cdk/drag-drop/directives/drop-list.ts#L322 https://github.com/angular/material2/blob/master/src/cdk/drag-drop/drop-list-ref.ts#L179

crisbeto commented 5 years ago

This would complicate things a lot. What is a use case where it would be useful?

volser commented 5 years ago

use case is lazy loading data while scrolling (it's common enough thing in modern apps)

volser commented 5 years ago

I know we don't have scrolling while dragging feature, but I was trying to implement workaround solution, almost works, but this bug... ((

djcurfew commented 5 years ago

Yeah this is certainly expected in a web app with lots of data loaded, other frameworks have support for it. Would be awesome to get this here!

theo2354 commented 5 years ago

This would complicate things a lot. What is a use case where it would be useful?

You simply have to delegate the problem. Give us a way to manually update the components.

JarekToro commented 5 years ago

This is the solution I have found. It has Pros and Cons but i believe it can be improved further.

Listen To Move Event From cdkDrag

          (cdkDragMoved)="moved($event)"

Call $event.source.dropContainer.start();

 moved($event: CdkDragMove<any>) {
      $event.source.dropContainer.start();
  }

How this works. When you call

 $event.source.dropContainer.start();

It runs this code

    this._siblings.forEach(sibling => sibling._startReceiving(this));

That tells the dynamically added DropList to start listening for cdkDrag Items.

Pros:

Cons:

akashkriplani commented 4 years ago

I am stuck in the same issue when using the cdkDropList inside an *ngIf whose value changes. The mentioned fix by @JarekToro also does not work for me. Do we have any other solution for this? I am currently using angular material v7.3.7

rebendajirijr commented 2 years ago

Unfortunately, the @JarekToro workaround does not work for me. Has anybody implemented some other way?

lecramr commented 2 years ago

I have the same problem, @JarekToro solution worked for me, but only 1-2 drags after that the whole drag drop functionality freezes and breaks. Have you found a workaround?

My goal is to have a hidden List on Top that only shows when the user is dragging.

JarekToro commented 2 years ago

For what's it's worth It is still working on my end. But it took a lot of small tinkering with the internals from what I can remember. I just took a peek at the old codebase that needed this. On thing I didn't mention was setting the

CdkDropList.connectedTo array to included the dynamically added list.

lecramr commented 2 years ago

So for anyone having the same problem I found a workaround and improved it further in #15139.

The cdkDropList has now three events:

<div cdkDropList (mousedown)="mousedown()" (mouseup)="mouseup()" (mousemove)="mousemove($event)">

In the controller:

private showDropArea: boolean = false;
private drag: boolean = false;
private startX = 0;
private startY = 0;

mousedown() {
    this.drag = true;
}

mouseup() {
    this.drag = false;
    this.startX = 0;
    this.startY = 0;
    this.showDropArea = false;
}

mousemove(event: any) {
    if (this.drag && !this.showDropArea) {
        if (this.startX == 0 && this.startY == 0) {
            this.startX = event.clientX;
            this.startY = event.clientY;
        }
        else {
            const diffX = Math.abs(event.clientX - this.startX);
            const diffY = Math.abs(event.clientY - this.startY);

            if (diffX > 1 && diffY > 1) {
                this.showDropArea = true;
            }
        }
    }
}

Hope someone finds this useful.

BenRacicot commented 2 years ago

I think I can replicate this but am not 100% sure.

There's two lists, A and B.

  1. List A is made up of items from an array and displayed via ngfor
  2. A drag item from A is being dragged
  3. The data is updated during the drag
  4. All D/D functionality becomes frozen

Is this what everyone else is experiencing?

nshaul commented 1 year ago

this code will not work with the ngIf

 <div  *ngIf="isDragging" class=""
                            cdkDropList id="newBoxZone" [cdkDropListData]="[]" [cdkDropListConnectedTo]="'newBoxZone'"
                            (cdkDropListDropped)="onDrop($event)">

                            <span>Drop here to create a new box</span>

                        </div>
boendermaker commented 1 day ago

I am experiencing some similiar issue with cdk dragdrop service, using no cdk drag directives together with ng-content projection and material table. (See here on my github Kitchensink)

When i add new data to the table the newly added rows arent't drag-sortable.

When i readd all draggables to the droplist after data has changed, dragging crashes at all and i get boundingrect not found exceptions on dragging a row.