Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drag and Drop with MatTable #13770

Closed
fbaezap opened this issue Oct 23, 2018 · 37 comments
Closed

Drag and Drop with MatTable #13770

fbaezap opened this issue Oct 23, 2018 · 37 comments
Assignees
Projects

Comments

@fbaezap
Copy link

fbaezap commented Oct 23, 2018

Bug, feature request, or proposal:

Feature request

What is the expected behavior?

Drag and drop with a drag handle and MatTable

What is the current behavior?

The drag handle is not being found. The ContentChildren on CdkDrag doesn't get it.

What are the steps to reproduce?

StackBlitz https://stackblitz.com/edit/angular-igmugp

What is the use-case or motivation for changing an existing behavior?

If the drag handle could be found, we could use drag and drop using a handle with a table

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular 7.0.0
Angular Material 7.0.1

@EHardy80
Copy link

Not to muddy the water, but this line of your StackBlitz solved an issue I was having with the previousIndex of the CdkDragDrop event (thanks btw!):
const prevIndex = this.dataSource.findIndex((d) => d === event.item.data);

Is there a known issue with event.previousIndex when used with MatTable?

@fbaezap
Copy link
Author

fbaezap commented Oct 30, 2018

Glad to help :)
I don't know if there is an issue with that :/ but I think it's because of using the same source for the drop and the table

@antoine-le-maire
Copy link

I'm also trying to implement drag and drop reorder in my material table and I'm having the same issue. Does anyone have a working example of it ?

By the way, I feel like this is a rather standard use case (drag and drop reorder in a material table). Wouldn't it make sense to have a working example of it in the angular material documentation about drag and drop ?

@samir-h
Copy link

samir-h commented Jan 18, 2019

@antoine-le-maire I implemented it, the problem was with the dragPreview. The solution is to implement ( remake ) the actual design of the row, because the styles were not applied by default.

@antoine-le-maire
Copy link

I think there are 2 problems around the table + drag and drop, both reproduced by the stackblitz above :

I believe you're talking about the 2nd problem here right ? If so, how did you re-design the row ? Did you read the width of each column in the dom to force it to the dragged element (jquery style) ?

@henry-phelps-ascendlearning-com

@antoine-le-maire did you find a solution to make cdkDragHandle work with the mat-table?

@samir-h
Copy link

samir-h commented Mar 7, 2019

@antoine-le-maire @henry-phelps-ascendlearning-com The workaround with the drag handle is to make the whole row dragable, then with css add pointer-events: none. Then on the element you want to be the drag handle you put pointer-events: all

@lemairea
Copy link

lemairea commented Mar 7, 2019

I did not find a solution, I had to let the whole row draggable. This is acceptable for now but this is a problem if you want to select text in the row for example.

@benediktberger
Copy link

@samir-h @lemairea : Can you provide a code snippet where to add the drag and drop directives? I cant make it work even with the whole mat-header-row draggable.

@henry-phelps-ascendlearning-com
Copy link

I got it to work using @samir-h suggestion. Here is an example: https://stackblitz.com/edit/angular-8tmeav . See lines 14 and 39 of app.component.html

@benediktberger
Copy link

Ah, sorry I was thinking about reordering the table columns. It did basically the same, using the mat-header-row as cdkDropList and adding cdkDrag to each mat-header-cell.

See https://stackblitz.com/edit/angular-cc77j7 . I can move the headers, but it doesn't even trigger the drop event afterwards. When moving the cdkDrag to the mat-header-row I can grab and drag the whole header row, but thats pointless :)
I was not able to get any further :(

@eliskaachee
Copy link

@antoine-le-maire I implemented it, the problem was with the dragPreview. The solution is to implement ( remake ) the actual design of the row, because the styles were not applied by default.

@samir-h, Do you have an example of redesigning the row so the styles apply? I'm currently having that issue.

@samir-h
Copy link

samir-h commented Mar 8, 2019

@eliskaachee Use the .cdk-drag-preview class , and then just reimplement the styles of how you want the element that is dragged to look. For example

.cdk-drag-preview {
  display: flex;
  width: 100%;

  .cell {
    display: flex;
    flex: 1 1 0%;
  }

// or other styles that you need to make the drag preview look like the actual table row

@SaiSirishaS
Copy link

@samir-h Your suggestion to add the "pointer-events: none" to the mat-row helped me solve the issue. But my table also has an Input. By making the Pointer events none I'll not be able to use Input.
Solution which I tried is applying "pointer-events: all" again on the Input alone but then it would be draggable again. Is there any solution for this?

@lujian98
Copy link

Come cross with drag and drop for the angular material table.
Here is my solution: https://github.com/lujian98/Angular-material-table-DnD.
You may have to change the data source interface if you want use it.

@lujian98
Copy link

Here is demo: https://stackblitz.com/edit/angular-p12rek

@1Paint
Copy link

1Paint commented Apr 22, 2019

@eliskaachee Use the .cdk-drag-preview class , and then just reimplement the styles of how you want the element that is dragged to look. For example

.cdk-drag-preview {
  display: flex;
  width: 100%;

  .cell {
    display: flex;
    flex: 1 1 0%;
  }

// or other styles that you need to make the drag preview look like the actual table row

Thank you for this!

For anyone having trouble, I had to use .mat-cell instead of .cell to get the styles applied:

  .mat-cell {
    display: flex;
    flex: 1 1 0;
    border-bottom-style: none;
  }

@FirstVertex
Copy link

It's not acceptable to set pointer-events: none on my table, as some columns have buttons. it is not intended for the user to initiate a drag and drop anywhere except the dragHandle, if specified. therefore this issue is definitely a BUG and needs to be addressed by Material team.

@FirstVertex
Copy link

FirstVertex commented Apr 26, 2019

I have achieved that UX by applying cdkDrag to the dragHandle itself, instead of the row, and using cdkDragRootElement to identify the row. It achieves the UX of dragging via handle, but there's still a bug that prevents the actual reordering after the drop.

See Stackblitz here.

Documentation of cdkDragRootElement is here.

Only remaining problem is (cdkDragDropped) event is never emitted with this setup.

@FirstVertex
Copy link

It would be nice if mat-table had a concept of a table body. That way the drag could be restricted to the body instead of the whole table.

@ajp76054
Copy link

So I ran across dealing with the drag handle situation recently on a project and while I think we should be able to use the dragHandle directive in a column def nothing I tried or from what I can tell nothing that others have tried have really worked.

@samir-h is right the pointer events do work however the UX is wrong for various reasons. This lead me to thinking that maybe there is a solution for now if we approach it a different way and here is what I came up with.

I start the table with cdkDragDisabled set to true this way the whole drag container is disabled for now. This allows the user to still interact with the table cells until they are ready to drag the row.

Then on the drag handle element I want to use I use (mousedown) to set the cdkDragDisabled to false. The caveat here is that you would think you could reset it to true with (mouseup) but it does not work so I have to set that inside the (cdkDropListDropped) event handler. This can be extended to work across two or more tables with the only difference there being that you need to listen for the (cdkDragExited) event to set that container back to disabled.

I have created a demo with the materials basic table example and just added the drag and drop to that on stack blitz here

@zehavibarak
Copy link

I have two cdkDropList, one on MatTable and the 2nd is a chip list. Dragging a chip to a table row (in a different component altogether) result in what appears to b a bug: the dragged chip is "stuck" on the 1st row that was dragged over, and the placeholder stays in place when dragging to another table row.

@EthanMelamed
Copy link

I have achieved that UX by applying cdkDrag to the dragHandle itself, instead of the row, and using cdkDragRootElement to identify the row. It achieves the UX of dragging via handle, but there's still a bug that prevents the actual reordering after the drop.

See Stackblitz here.

Documentation of cdkDragRootElement is here.

Only remaining problem is (cdkDragDropped) event is never emitted with this setup.

This was almost a perfect solution for me. The only outstanding issue is that I can no longer scroll the page by swiping this list using touch. It actually works somewhat intermittently but I can't understand why. Every 2nd or 3rd scroll swipe seems to take

@kmcs
Copy link

kmcs commented Sep 30, 2019

The example https://stackblitz.com/edit/angular-p12rek from above does not work with angular 8.2.5 (probably also versions after that) and tsconfig.json angularCompilerOptions.enableIvy = true. It looks like the cdkDropList* attributes are missing, you can drag the column header around the whole page.

@cjardine
Copy link

cjardine commented Nov 13, 2019

Had the same issue regarding table cells and assigning a drag handle. My workaround was to add a directive to non-draggable table cells in the draggable row that cancels bubbling of the mousedown event down to cdkDrag instance.

I believe the following solution is better when you need interactivity within the cells. In that case, the css solution (pointer-events: none) mentioned by @samir-h, as well as the mouse event workaround mentioned by @ajp76054 have some difficulties.

Please see my StackBlitz here: https://stackblitz.com/edit/angular-tgrcni

Here is a related StackOverflow: https://stackoverflow.com/questions/55028318/how-to-make-a-mat-table-row-drag-drop-work-with-cdkdraghandle-so-that-the-row-is/58828917#58828917

Hope this helps.

@sgrillon14
Copy link

Démo online: https://stackblitz.com/edit/angular-hrulnj

image

@rosostolato
Copy link
Contributor

rosostolato commented Jan 27, 2020

To solve it on my component I first added drags and handles references:

  @ViewChildren(CdkDragHandle) handles: QueryList<CdkDragHandle>;
  @ViewChildren(CdkDrag) drags: QueryList<CdkDrag>;

then on ngAfterViewInit() I added the following code:

  ngAfterViewInit() {
    combineLatest([this.drags.changes, this.handles.changes])
      .pipe(
        startWith([]),
        map(() =>  _.zip(this.drags.toArray(), this.handles.toArray())),
        delay(100), // waits for cdk to finish his work
        mergeAll()
      )
      .subscribe(([drag, handle]) => {
        drag._dragRef.withHandles([handle.element]);
      });
  }

Here is the demo implemented

@Falven
Copy link

Falven commented Feb 24, 2020

@rosostolato Your code doesn't work.

@jadekler the event.previousIndex issue still persists with @angular/material ^9.0.1

I've kind of narrowed in on the issue.
I believe that the _draggables list of draggables in drag-drop.js:1850 contains the original item positions; it does not get updated, and when it tries to get the previous index, it returns the original index. I could be wrong. It's late. Could someone verify?

@rosostolato
Copy link
Contributor

@Falven did you check the demo that I adjusted? It's working correctly and I even use it in my projects.

@jeanbza
Copy link
Contributor

jeanbza commented Feb 24, 2020

@Falven

@jadekler the event.previousIndex issue still persists with @angular/material ^9.0.1

The bug appears to be fixed in dev. The example I'm working on in #18456 works at HEAD without my previous cludgy re-mapping. If I had to guess I'd say it's just waiting for a 9.0.2 release or something. :)

@Falven
Copy link

Falven commented Feb 24, 2020

@jadekler Thanks!
Slightly off-topic, but would you happen to know if the latest angular/components repo HEAD can be installed via NPM using the Github dependency format?
Something like "@angular/components": "angular/components#master"?

@jeanbza
Copy link
Contributor

jeanbza commented Feb 24, 2020

I'm definitely not very knowledageable about npm/nodejs, but I think you can clone components to your local machine and then use npm link to force npm to use it instead of a remote copy.

But, yeah, never done any of that myself, so I might be totally wrong! :)

@crisbeto
Copy link
Member

crisbeto commented Feb 24, 2020

Each commit to master is published to https://github.com/angular/cdk-builds and https://github.com/angular/material2-builds.

@Falven
Copy link

Falven commented Feb 24, 2020

@crisbeto Thanks for that!
For future people wondering:

"@angular/cdk": "angular/cdk-builds#master",
"@angular/material": "angular/material2-builds#master",

In package.json worked for me albeit giving me the message: npm WARN @angular/material@9.1.0-sha-1ba8b26b2 requires a peer of @angular/cdk@9.1.0-sha-1ba8b26b2 but none is installed. You must install peer dependencies yourself.

@jeanbza
Copy link
Contributor

jeanbza commented Feb 28, 2020

@crisbeto is this issue ready to be closed, now that angular/material.angular.io#727 is in?

@mmalerba mmalerba added the needs triage This issue needs to be triaged by the team label May 20, 2020
@crisbeto
Copy link
Member

Closing since the related PR has been merged in.

@crisbeto crisbeto added area: cdk/drag-drop and removed needs triage This issue needs to be triaged by the team labels May 25, 2020
@crisbeto crisbeto added this to Triaged in triage #1 via automation May 25, 2020
@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Jun 25, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
No open projects
triage #1
  
Triaged
Development

No branches or pull requests