SortableJS / Sortable

Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.
https://sortablejs.github.io/Sortable/
MIT License
29.63k stars 3.7k forks source link

how to cancel drop in onEnd? #837

Closed Leonidnei closed 8 years ago

Leonidnei commented 8 years ago

I'm trying to use sortable with aurelia. I want to prevent changing DOM by sortable. Is there a way to cancel drop in onEnd?

Jonathancollinet commented 8 years ago

You can't cancel drop in onEnd statement because the element was dropped. You can try to pass disabled property to false when you don't want to drop in other statement (like onAdd), or remove the dropped model when you loop on evt.models in onEnd callback.

RubaXa commented 8 years ago

Nohow.

damianof commented 8 years ago

Would be nice to see a comment about what the recommended approach would be for this. I'm using sortable within Aurelia and had all sort of issues Aurelia was causing because sortable changes the dom. I'd rather cancel the move/add and just update the arrays and let Aurelia update its bindings.

ben-girardet commented 8 years ago

Same here. I'm using Aurelia and would like to use Sortable in my projects. Really need the cancelation of dom manipulation.

damianof commented 8 years ago

I ended up switching to Dragula for the time being, until we can have some additional functionality on Sortable.

ben-girardet commented 8 years ago

Haha... funny things, I've been using Dragula since I started working with Aurelia but would like to switch to Sortable now and find out it's hard without ugly hacks... Will probably end up doing same as you! Thanks for your heads up!

ghost commented 7 years ago

I am also looking for this functionality. Might go with Dragula as well.

mavenik commented 7 years ago

I am using Sortable to drop elements across sortable lists. I was able to do this by explicitly removing the child element from DOM in onAdd callback with this:

onAdd: function(addEvent) {
    [...]
    droppedElement = $($(addEvent.to).children()[addEvent.newIndex]).remove();
    [...]
} // onAdd

I'm using Sortable with VueJS and wasn't sure of using vue-draggable yet. This is still WIP and my model binding is flaky as of now, but I needed a quick way to retain DOM control entirely with Vue while extracting essential data from the event.

I don't like this solution but it does the job ATM. Hope this helps someone.

awsafanam commented 6 years ago

if anyone is still looking for a solution, I needed to make the first element to stay always in the first place and make it not draggable. i added the class 'dont-sort' to that element and passed filter: '.dont-sort' to sortable. But still if user dragged other elements in place of this element it would move to the next place. so I added the codes below to bring that element back to first place (using jquery) onEnd: (evt) => { if(evt.newIndex === 0) { $(".dont-sort").parent().prepend($(".dont-sort")); } } Hope that helps someone.

xyyVee commented 5 years ago

I have also encountered this problem in Vue, my situation is: I have one stable list on the top, and one normal list after stable list, I needed to stop dropping when item from one list to another list. At first i plan to set two group width Sortable.create but since i use element-ui so i failed. And my finally solution is to change the dom element directily like:

onEnd: evt => {
    if (condition) {
        const childNode = el.querySelectorAll('tr')
        if (evt.oldIndex > evt.newIndex) {
            parentNode.insertBefore(childNode[evt.newIndex], childNode[evt.oldIndex + 1])
        } else {
           parentNode.insertBefore(childNode[evt.newIndex], childNode[evt.oldIndex])
        }
        return false
    }
    // change normal position
    const targetRow = this.list.splice(evt.oldIndex, 1)[0]
    this.list.splice(evt.newIndex, 0, targetRow)
}

And still looking for good solution also.

Jasonlhy commented 4 years ago

I found out that it is possible to cancel in onMove

https://jsbin.com/nawahef/edit?html,js,output

boena commented 3 years ago

If anyone else is looking for a solution, I used the onMove and put a class on the first element ignore-drag. Then used this code to cancel the move if class existed on the hovered element. So this works also if you wish to be able to lock the last element etc.

onMove(event) {
    if(event.related && event.related.classList.contains('ignore-drag')) {
      return false
    }
 }
dustout commented 3 years ago

I found a similiar solution to @xyyVee, but made some small tweeks so that it only uses the evt parameter and uses a generic tag name

 sortableSettings.onEnd = function (evt) {
    //undo the move in html
    var tagName = evt.item.tagName;
    var items = evt.from.getElementsByTagName(tagName);
    if (evt.oldIndex > evt.newIndex) {
        evt.from.insertBefore(evt.item, items[evt.oldIndex+1]);
    }
    else {
        evt.from.insertBefore(evt.item, items[evt.oldIndex]);
    }

    //redo the move in angular/vue/blazor/etc...
    //dotNetHelper.invokeMethodAsync('SwapList', evt.oldIndex, evt.newIndex);
};
l2aelba commented 3 years ago

Try this:

Support also for nested items

onEnd (e) {
  let condition = true // Your condition here
  if (condition) {
    const items = e.from.querySelectorAll(':scope > div') // You can change this if needed (example: draggable: '.my-item' change to :scope > .my-item)
    e.from.insertBefore(e.item, items[e.oldIndex + (e.oldIndex > e.newIndex)])
    return false
  }
}
kjantzer commented 2 years ago

I too needed to prevent changing the DOM to work with lit.dev However, I needed the element to return to the EXACT location (in between comments added by lit-html)

This seems to be working well for me:

onChoose(e){
    e.item.placeholder = document.createComment('sort-placeholder')
    e.item.after(e.item.placeholder)
},
onSort(e){

    // put back in original location
    if( e.item.placeholder ){
        e.item.placeholder.replaceWith(e.item)
        delete e.item.placeholder
    }

    // add your logic to save sort and update DOM
}
Ben-Avrahami commented 1 year ago

found a solution here https://lightrun.com/answers/sortablejs-sortable-prevent-lib-from-manipulating-the-dom-vuejs for me using event.item.remove() solved the problem of both vue and Sortable updating the dom and causing unwanted behaviors and duplication.