Sortable: Is it possible to drag one element, but drop another?

Created on 26 Jan 2016  路  6Comments  路  Source: SortableJS/Sortable

Question.

I am trying to drag an element from one sortable list, and then drop the item into a different sortable list. Upon drop I want to replace the element with a graphic representation of that element.

For example, I have a list of elements like:
<div id="circle">circle</div>
<div id="square">square</div>
<div id="triangle">triangle</div>

I then want to drag these elements into a new list, where dropping the element will leave an element like:
<img src="circle.png" />
or
<img src="square.png" />
or
<img src="triangle.png" />

I have tried to use the onAdd event within the receiving sortable to convert the element. This does sort of work, but this seemingly the wrong event. Before this event fires you can briefly see the word "circle" within the sortable list, which is bad for the user experience. Ideally only the graphic representing the shape would display.

You can roughly see what I'm trying to do here:
https://output.jsbin.com/figedu

Any ideas on how to make something like this work? A cursory review of the code shows that there does not appear to be an onDragOver event, which is where I would have expected to be able to implement something to achieve my goal. Maybe there is another way?

thanks

question

Most helpful comment

Expanding on @RubaXa's comment for future reference: I've most commonly needed this feature in "builder" / "editor" applications, where there's a toolbox of items that can be dragged onto a workspace to position / reorder them. The workspace view is often very different from the toolbox view.

In this case, you can nest both the toolbox and workspace views within the items being dragged / sorted, then selectively show one or the other depending on parent:

<div id="toolbox">
  <div class="item">
    <div class="view toolbox-view">show this in toolbox</div>
    <div class="view workspace-view">show this in workspace</div>
  </div>
  <!-- more items -->
</div>
<div id="workspace"></div>
.item > .view { display: none; }
#toolbox > .item > .view.toolbox-view { display: block; }
#workspace > .item > .view.workspace-view { display: block; }

It's a bit of a kludge, but it works, and it's also a usable approach if you're working with reactive component libraries. (In cases where this doesn't work as well - e.g. dragging items from an HTML toolbox to an SVG workspace, or use cases that require 2D positioning instead of linear reordering - you're often better-served by using HTML5 drag-and-drop directly.)

All 6 comments

Figured it out, this can be closed.

This probably is not officially supported behavior, but at least with the current codebase you can accomplish the goal by doing the following with the onMove handler for the donor sortable (using a little jquery in this case):

        onMove: function (evt) {
          $(evt.dragged).html(getNewNode());
        },

The above works, but it introduces some quirky behavior whereby the now replaced node can possibly move back into the donor list and trash your UI.

Not too much of a problem though, you can block the updated element from being able to move back:

        onMove: function (evt) {
          if (evt.from === evt.to) {
            return false;
          }

          $(evt.dragged).html(getNewNode());
        },

So when you want to move the element back to its original list it disappears?

@martinsik: I wish it did. All the above code does is prevent you from dragging it back to the original list.

I personally ended up going in a different direction here entirely, as I want a donor list to drop elements, but I want to be able to "block" a drop, and I want to be able to remove elements. Neither of these features is supported, and seemingly for good reason.

Use CSS depending on the parent for this purpose.

Expanding on @RubaXa's comment for future reference: I've most commonly needed this feature in "builder" / "editor" applications, where there's a toolbox of items that can be dragged onto a workspace to position / reorder them. The workspace view is often very different from the toolbox view.

In this case, you can nest both the toolbox and workspace views within the items being dragged / sorted, then selectively show one or the other depending on parent:

<div id="toolbox">
  <div class="item">
    <div class="view toolbox-view">show this in toolbox</div>
    <div class="view workspace-view">show this in workspace</div>
  </div>
  <!-- more items -->
</div>
<div id="workspace"></div>
.item > .view { display: none; }
#toolbox > .item > .view.toolbox-view { display: block; }
#workspace > .item > .view.workspace-view { display: block; }

It's a bit of a kludge, but it works, and it's also a usable approach if you're working with reactive component libraries. (In cases where this doesn't work as well - e.g. dragging items from an HTML toolbox to an SVG workspace, or use cases that require 2D positioning instead of linear reordering - you're often better-served by using HTML5 drag-and-drop directly.)

HTML

<div class="container">
  <div class="left">
    <div>item - 1</div>
    <div>item - 2</div>
    <div>item - 3</div>
    <div>item - 4</div>
    <div>item - 5</div>
  </div>
  <div class="right">
    <div>item - 1</div>
    <div>item - 2</div>
    <div>item - 3</div>
    <div>item - 4</div>
    <div>item - 5</div>
  </div>
</div>

JS

$(document).ready( function() {
 $('.left').sortable({
    group: {
        name: 'shared',
        pull: 'clone',
        put: false
    },
    animation: 150,
    sort: false,   
 });
 $('.right').sortable({
   group: 'shared',
   animation: 150,
   onAdd: function (evt) {
        let randData = Math.ceil(Math.random()*1000);
    $(evt.item).replaceWith($('<div>' + randData + '</div>'));
    },   
 });
});

https://codepen.io/borodin-i/pen/OJLovQr

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tom-sherman picture tom-sherman  路  3Comments

artaommahe picture artaommahe  路  4Comments

Webifi picture Webifi  路  3Comments

dwburdick picture dwburdick  路  3Comments

seltix5 picture seltix5  路  3Comments