I have a drag and drop component (using Sortable) but I can't figure out the logic to update the list order once the the item is dropped into it's new location.
Code (Vue.js):
new Vue({
el: '#app',
template: '#dragdrop',
data() {
return {
list: [
{name: 'Item 1', id: 1, order: 0},
{name: 'Item 2', id: 2, order: 1},
{name: 'Item 3', id: 3, order: 2},
{name: 'Item 4', id: 4, order: 3},
{name: 'Item 5', id: 5, order: 4},
{name: 'Item 6', id: 5, order: 5},
],
}
},
ready() {
Sortable.create(document.getElementById('sort'), {
draggable: 'li.sort-item',
ghostClass: "sort-ghost",
animation: 80,
onUpdate: function(evt) {
console.log('dropped (Sortable)');
}
});
},
methods: {
dropped() {
console.log('dropped (Vue method)');
}
}
});
I have a working JSFiddle: https://jsfiddle.net/jackbarham/rubagbc5
I'm looking to get the order
in the array to sync up so I can make an AJAX update once the item is dropped.
This is not the most elegant solution but I think it works. This uses the Sortable onUpdate
handler to update the underlying array. Whenever an item is dragged to a new position, it gets moved to the same location in the array - this way the view model stays in sync with what's displayed in the view. Then the item order
properties get updated to match their new positions in the array.
new Vue({
el: '#app',
template: '#dragdrop',
data() {
return {
list: [
{name: 'Item 1', id: 1, order: 0},
{name: 'Item 2', id: 2, order: 1},
{name: 'Item 3', id: 3, order: 2},
{name: 'Item 4', id: 4, order: 3},
{name: 'Item 5', id: 5, order: 4},
{name: 'Item 6', id: 6, order: 5},
],
}
},
ready() {
var vm = this;
Sortable.create(document.getElementById('sort'), {
draggable: 'li.sort-item',
ghostClass: "sort-ghost",
animation: 80,
onUpdate: function(evt) {
console.log('dropped (Sortable)');
vm.reorder(evt.oldIndex, evt.newIndex);
}
});
},
methods: {
reorder(oldIndex, newIndex) {
// move the item in the underlying array
this.list.splice(newIndex, 0, this.list.splice(oldIndex, 1)[0]);
// update order properties based on position in array
this.list.forEach(function(item, index){
item.order = index;
});
}
}
});
You can optimize the reorder()
method if you need to.
Here's an updated version of your jsfiddle.
I feel like this is the kind of functionality that one should try to package up into a custom directive but I haven't figured out exactly how to do that yet.
I created a Vue.js ic directive to handle this kind of update in a generic way. It can be used exactly as v-for directive but add the drag and drop capacity and corresponding updates on the view model array.
Usage:
<div v-dragable-for="element in list">{{element.name}}</div>
Demo:
.
Fiddle: example 1, example 2
GitHub: Vue.Dragable.For
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With