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

how to cancel drop in onEnd? #837

Closed
Leonidnei opened this issue Apr 27, 2016 · 17 comments
Closed

how to cancel drop in onEnd? #837

Leonidnei opened this issue Apr 27, 2016 · 17 comments
Labels
question questions from the community

Comments

@Leonidnei
Copy link

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
Copy link

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 RubaXa added the question questions from the community label Jul 6, 2016
@RubaXa
Copy link
Collaborator

RubaXa commented Jul 6, 2016

Nohow.

@RubaXa RubaXa closed this as completed Jul 6, 2016
@damianof
Copy link

damianof commented Sep 1, 2016

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
Copy link

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

@damianof
Copy link

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

@ben-girardet
Copy link

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
Copy link

ghost commented Oct 30, 2016

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

@mavenik
Copy link

mavenik commented Oct 23, 2017

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
Copy link

awsafanam commented Apr 3, 2018

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
Copy link

xyyVee commented Feb 13, 2019

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
Copy link

Jasonlhy commented Jan 8, 2020

I found out that it is possible to cancel in onMove

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

@boena
Copy link

boena commented Jan 13, 2021

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
Copy link

dustout commented Aug 9, 2021

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
Copy link

l2aelba commented Oct 1, 2021

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
Copy link

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
Copy link

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.

@BalusC
Copy link

BalusC commented Jan 21, 2025

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

}

For lit.dev users, check #2089 for more lit.dev targeted solutions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question questions from the community
Projects
None yet
Development

No branches or pull requests