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.16k stars 3.68k forks source link

[Knockout] Can't drag and drop anymore #712

Closed stockmansy closed 8 years ago

stockmansy commented 8 years ago

Drag and drop is currently not working with the new version of knockout (3.4.0) When you drop an item, it disappears because knockout doesn't properly refresh the list anymore.

The issue has something to do with the following line:

Under "moveItem = function (itemVM, from, to, clone, e) {" :

//Make sure to tell knockout that we've modified the actual array. to.valueHasMutated();

srosengren commented 8 years ago

If i read https://github.com/knockout/knockout/releases this (Possible compatability issues item 3) correctly we will now have to use call/apply with the observable itself with valueHasMutated.

Should be an easy PR if you want to @mensaap ?

srosengren commented 8 years ago

@mensaap I've been (unsuccessfully) trying to reproduce this using this example file https://github.com/RubaXa/Sortable/blob/dev/knockout/example.html and replacing knockout 3.3 with 3.4. Do you have a repro?

adriaanmeuris commented 8 years ago

I did reproduce this one in a project I'm working on, I'll try to reproduce with the example code.

adriaanmeuris commented 8 years ago

I've reproduced the issue: https://jsfiddle.net/adriaanmeuris/4voe0jv2/2/ You'll see that items disappear if you sort them in the "selected columns" list.

it is caused by the new option in KO to defer updates (see http://knockoutjs.com/documentation/deferred-updates.html) ko.options.deferUpdates = true;

If you set this to option to false, items won't disappear anymore.

I'm not familiar enough with the code of Sortable to do a PR myself, but does this help you to fix the issue?

adriaanmeuris commented 8 years ago

I just did some more tests, and could fix the issue without setting deferUpdates to false.

Right before you splice & mutate the "to" array, you can force updates to the UI in Knockout:

// force updates so the UI will see a delete/add rather than a move
ko.tasks.runEarly();

//Insert the item on its new position
to().splice(newIndex, 0, itemVM);   

//Make sure to tell knockout that we've modified the actual array.
to.valueHasMutated();

More info: http://knockoutjs.com/documentation/deferred-updates.html#forcing-deferred-notifications-to-happen-early

I also tried extending my observables using .extend({ notify: 'always' }); like the Knockout documentation states, however this doesn't work (I guess this is only useful when using computed observables).

RubaXa commented 8 years ago

Moved to https://github.com/SortableJS/knockout-sortablejs