angular / components

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

Drag Drop Sortable, mixed orientation support #13372

Closed abdulkareemnalband closed 5 months ago

abdulkareemnalband commented 6 years ago

Feature request,

Mixed direction support, such as items placed by flex-wrap: wrap

What is the expected behavior?

Should be able to use sortable drag drop on both vertical and horizontal axis at the same time

What is the current behavior?

Only vertical or horizontal is supported

What are the steps to reproduce?

https://stackblitz.com/github/vbwioxyq

Github repo link

https://github.com/abdulkareemnalband/ng-drag-drop/tree/prebuilt-css

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

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/

Angular CLI: 7.0.0-beta.4
Node: 8.11.4
OS: win32 x64
Angular: 7.0.0-rc.0
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, platform-server, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.9.0-beta.4
@angular-devkit/build-angular     0.9.0-beta.4
@angular-devkit/build-optimizer   0.9.0-beta.4
@angular-devkit/build-webpack     0.9.0-beta.4
@angular-devkit/core              7.0.0-beta.4
@angular-devkit/schematics        7.0.0-beta.4
@angular/cdk                      7.0.0-beta.2
@angular/cli                      7.0.0-beta.4
@angular/flex-layout              6.0.0-beta.16
@angular/material                 7.0.0-beta.2
@ngtools/webpack                  7.0.0-beta.4
@schematics/angular               7.0.0-beta.4
@schematics/update                0.9.0-beta.4
rxjs                              6.3.3
typescript                        3.1.1
webpack                           4.19.1
100cm commented 6 years ago

@jelbourn hey ,have any progress about this issue now?

IhorHolovatsky commented 6 years ago

Are there any workarounds for drag and drop in mat-grid-list (reordering items in the grid)?

I have an idea, to mark each item in the grid as 'cdkDropList', and handle reordering as dropping item from one cdkDropList to another

  <mat-grid-list [cols]="photoCols"
                       rowHeight="1:1"
                       gutterSize="20px">
          <mat-grid-tile *ngFor="let photo of photos$ | async"
                         cdkDrag
                         cdkDropList
                         (cdkDragEnded)="dragEnded($event)">
            <app-photo-item [Photo]="photo"
                            (OnSelectionChange)="onSelectionChange($event)"></app-photo-item>
          </mat-grid-tile>
</mat-grid-list>

If it will work, I will provide demo

vupham-zingbox commented 6 years ago

How come the demo gif shows different with what it can provide ? https://cdn-images-1.medium.com/max/800/1*i30ZQdBC7CKbXXdOrUNQcg.gif

100cm commented 6 years ago

@vupham-zingbox +1 , i want to know how to implement what the demo shows

abdulkareemnalband commented 6 years ago

@IhorHolovatsky Nice idea but only works when no of items in per row is known before hand But when content reflows on window resize, this is not pretty

demisx commented 6 years ago

Would be nice if what's shown in the demos was actually backed up by the framework code.

BovineEnthusiast commented 6 years ago

Copy and pasting my comment from #13889 since it was a duplicate:

To give an example of the issue, I have a horizontal list of photos that needs to wrap (using fxLayout="row wrap", as the issue description states). However, when it spans multiple lines, it breaks:

drag

ducalai commented 6 years ago

Any progress about this issue?

100cm commented 6 years ago

Almost a month has passed , any update now ?

eduardogiorgio commented 6 years ago

Any progress about this issue?

PhoebePan commented 6 years ago

@MrSnappingTurtle Do you have demo code of multiple list wrap? Thanks :)

100cm commented 6 years ago

Although i know to achieve this feature is very hard. but I still want to ask "any progress about this issue?"

hristo-iliev commented 6 years ago

Is there any progress on this one? Or eventually any idea of when it would be implemented?

AsafAgranat commented 5 years ago

This is difficult to implement in the current way it was implemented in the CdkDrag directive. The positioning of the placeholder, and the positions of each item that is clearing way for the placeholder, are done by setting inline CSS transforms to each of the involved elements. This is done in a predictable fashion, meaning that since the dimensions of the dragged element are known from the moment it is dragged, it can be calculated for each of the elements in the list how many pixels they should be shifting back/forth. The calculation is eased further by limiting the transforms to a single axis, allowing the transforms to ignore the widths (or heights in horizontal mode) of elements in the list.

On the other hand, when a list is wrapping, the wrapped elements are being wrapped in an arbitrary manner, calculated by the browser. When so, it is impossible to translate (transform) list elements in a similar predictability, because it is not known (upon drag event) which list elements are wrapping, and where they are positioned relatively within the list.

To circumvent that, upon every drag event, a new snapshot of the list (and all connected lists) must be generated, where the list DOM is being traversed, and each list element gets registered for width and height (practically creating a matrix). Considering that Material devs tried to solve this directive through a performative approach, traversing the DOM and registering each element is not an option as it taxes the browser significantly, and veers from the predictability approach.

Alternatively, a middle ground can be implemented. It is less performative than current solution, but at the same time does not require any heavy calculations. Instead of shifting elements via transform, the placeholder element should be moved (currently it remains in the place of the original dragging element), to be positioned before or after the target drop element. It then could animate the max-height property (or max-width for horizontal). This, as I mentioned, is less performative, but it does allow to shift the placeholder anywhere in the list - even in a wrapping list.

allenz0810 commented 5 years ago

for time being you can take a look this - https://github.com/smnbbrv/angular-sortablejs-demo/tree/master/src/app/examples/multiple-lists

flolu commented 5 years ago

Thank you! I appreciate your help, I'll check it out.

Best regards, Flo

c3rber commented 5 years ago

here is a workaround with using multiple lists https://stackblitz.com/edit/angular-nuiviw

100cm commented 5 years ago

@c3rber That was wonderful! You are my best friend! Thanks a lot ! i will try it.

NurGuz commented 5 years ago

@c3rber Wow, it's work for me, thx.

But.... Any OFFICIAL progress about this issue? It's for make and standar to this.

Thx

RobinBomkampDv commented 5 years ago

@c3rber Yeah, it is working fine.

Is there a way of animating @c3rber workaround?

NurGuz commented 5 years ago

@c3rber

Don't work correcty.

If u add a button, for example, for add new items and after reorder the items doesn't work. If you move the ultimate element in tother place don't reorganize correctly

I think that the problem is <div class="example-container" cdkDropListGroup> besacuse @ViewChild(CdkDropListGroup) listGroup: CdkDropListGroup<CdkDropList>; don't update correctly

c3rber commented 5 years ago

@NurGuz Check it out. I added an example. https://stackblitz.com/edit/angular-nuiviw

Placeholder was moved outside the model and also type of data changed from string[][] to items: Array<number> = [1, 2, 3, 4, 5, 6, 7, 8, 9];

NurGuz commented 5 years ago

@c3rber GJ man! It's okey!

I'm going to try it in my application

flolu commented 5 years ago

I really appreciate your help about this issue, but someting isn't quite working:

In the Stackblitz demo (https://stackblitz.com/edit/angular-nuiviw) everything works fine. I exactly coppied the code into my project and the following happens:

[image: dragdropbug.png] Sometimes, the wrong item is greyed out. But when releasing the mouse the dragged item goes to the right place.

It would be really nice if someone can help me out with this!

Thanks, Flo

On Thu, 20 Dec 2018 at 10:22, NurGuz notifications@github.com wrote:

@c3rber https://github.com/c3rber GJ man! It's okey!

I'm going to try it in my application

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/angular/material2/issues/13372#issuecomment-448929235, or mute the thread https://github.com/notifications/unsubscribe-auth/Agm6TYSlED1-n9huliaOWscdghRVR9bhks5u61bLgaJpZM4XB1j0 .

GekkePeer commented 5 years ago

@c3rber Nice solution, although it doesn't work quite well on divs with different width-sizes. Any solution for this?

raphael22 commented 5 years ago

@crisbeto This issue should labeled "critical" as most use-cases with responsive design need multi-line support.

daveschwerstein commented 5 years ago

@c3rber Fantastic solution. This is exactly what we were looking for.

100cm commented 5 years ago

Last year , I subscribe this problem , today i hope this problem could be solve in 2019. waiting for it.

CAspeling commented 5 years ago

Hi all,

If you want that example from @c3rber to work with material grid list (singular), then just change the content of the example container to :

<mat-grid-list
    cdkDropList
    [cdkDropListEnterPredicate]="enter"
    (cdkDropListDropped)="drop()"
    #placeholder
    [gutterSize]="15"
    [cols]="1"
    [rowHeight]="100"></mat-grid-list>

  <mat-grid-list cdkDropList *ngFor="let item of items"
       [cdkDropListEnterPredicate]="enter"
       (cdkDropListDropped)="drop()"
       [gutterSize]="15" [cols]="2" [rowHeight]="100">
    <mat-grid-tile
      cdkDrag
      class="example-box"
      [colspan]="1"
      [rowspan]="2">
      {{item}}
    </mat-grid-tile>
  </mat-grid-list>

and make sure to change the width of example box in the css to :

width: 200px !important;

I'll try and get a demo up over the weekend. Feel free to change columns and rows to see what suits.

I'll be looking further into why this actually works because in my mind, there should be two grid lists and a For loop to create tiles, but in this example, there are many grid lists, one for each tile and then the placeholder as well.

image

Note: obviously, you'd have to also include material package and correct module.

devtician commented 5 years ago

@skatestyle Do you have the same version of the cdk installed as in the demo (7.1.1)?

flolu commented 5 years ago

@devtician Nope, I am currently using 7.2.0

devtician commented 5 years ago

@skatestyle You need to switch to version 7.1.1, because I found that after 7.1.1 some behaviour was changed (not sure what exactly), but this solved it for me.

CAspeling commented 5 years ago

@devtician even in the demo itself without changing or copying anything over to anywhere else, there is the bug on position 0 when dragging from elsewhere (generally when going diagonally). sometimes it happens, sometimes it doesn't. I've not been able to make it happen when dragging to any other position.

pas2al commented 5 years ago

@crisbeto @jelbourn Can you give us any kind of update regarding this issue? I don't think that most of the community or if i speak for myself expect that you give us a timeframe for this feature or that this will be implemented at all. You do amazing work here, but some kind of communication would be helpful. There is no comment from the Angular team on this pretty high discussed issue. I just want to ask you kindly to make communication a little bit more transparent so that we can understand why there is no update since this issue was opened.

yasselavila commented 5 years ago

@StephenFluin posted on his blog a really good demo: https://stackblitz.com/edit/drag-drop-dashboard Link to post: https://fluin.io/blog/things-I-wish-I-knew-about-CDK-drag-drop

I've been playing around and it works well, you can achieve some cool things... My test: https://stackblitz.com/edit/yag-dnd-dashboard

It even works on IE11 👍

krusli commented 5 years ago

A few notes after implementing the workaround:

image

See my Gist for relevant code.

Dragging an item initially from the index 0 to the index 4 as follows: 0 -> 1, 1 -> 2, 2 -> 5, 5 -> 4, the last 5 -> 4 drag does not register.

For now actively telling the (injected) change detector (cd: ChangeDetectorRef) to detect changes as soon as a new ckdDropList works at the cost of firing the handler one extra time each move (0 -> 1, 1 -> 1 instead of just 0 -> 1 for example) as the view updates.

willbeaufoy commented 5 years ago

We need this too.

flauc commented 5 years ago

@krusli works perfectly, thank you 👍

mkarras commented 5 years ago

@krusli Thx for your solution! Using it with cards, also with animation. Need only some little fixing to work perfect. One question. You wrote „... some extra stuff I didn't need“. What do you mean with that? Is there a other behaviour to the workaround of c3rber?

krusli commented 5 years ago

@mkarras taking a look at it again, it's just the lack of manually removing and adding HTML elements on the page and notifying the ChangeDetectorRef instead. From the other StackBlitz example it's just the lack of the QueryList stuff.

Functionally they should all be the same/have the same basic idea: get around the problem by using our own data for each cdkDropList and cdkDrag (indices in my example for both cdkDropList and cdkDrag, although you can use different things depending on what you need), then handle the rearranging logic ourselves using said data (calling moveItemsInList or other helpers as needed).

denkerny commented 5 years ago

@krusli hey man, but how it will look for this approach? https://stackoverflow.com/questions/54590576/angular-cdk-drag-and-drop-resize mb u have an idea..

qichangjun commented 5 years ago

I'm using dnd2 now. Hope to have the official solution

denkerny commented 5 years ago

@qichangjun hm, but it looks like it isn't supported ( https://github.com/akserg/ng2-dnd/issues/274

krusli commented 5 years ago

@kernyden I've only looked at your code a bit so I'm not quite sure about what you're using cdkDrag for. Are you using it to rearrange items, or just to resize the boxes on your page?

denkerny commented 5 years ago

@krusli im using cdkDrag for rearrange, grabber and resizable (custom) directives r used for resize.

FritzHerbers commented 5 years ago

@kernyden I probably have dragging problems due to size issues: https://github.com/angular/material2/issues/14093#issuecomment-462395200

In your previous comment you referred to StackOverflow: https://stackoverflow.com/questions/54590576/angular-cdk-drag-and-drop-resize However the source is incomplete. Can you please provide the complete source (or better make a StackBlitz, making communication for fixes easier).

CarlosTorrecillas commented 5 years ago

This would be nice to have it sorted soon. We also need it.

andreElrico commented 5 years ago

I have found this incredibly interesting project here: (has no 3rd party dependencies).

https://github.com/swiety85/angular2gridster

DEMO

spiritintheshiftkey commented 5 years ago

@yasselavila Your solution worked well for me!

You can save the hassle of using @ViewChildren to get the drop list connections by wrapping the grid list in a cdkDropListGroup:

<div class="wrapper" cdkDropListGroup>
    <mat-grid-list [cols]="responsiveColumns" rowHeight="1:1">
        <mat-grid-tile *ngFor="let item of items; let i = index">
            <cdk-drop-list [cdkDropListData]="i">
                <div cdkDrag (cdkDragDropped)="handleDrop($event)" [cdkDragData]="i">
                    <!-- contents of draggable item -->
                </div>
            </cdk-drop-list>
        </mat-grid-tile>
    </mat-grid-list>
</div>

I have some logic that is called when an item is dropped, so I used cdkDragDropped rather than cdkDragEntered, which would have triggered too many calls.

yasselavila commented 5 years ago

@spiritintheshiftkey Thank you. Your suggestion helped me reduce some code 👍