sealla sealla - 15 days ago 6
Javascript Question

Sortable.js with Vue 2.0 sorts incorrectly

I am using Sortable.js and Vue.js. The goal is to sort items and keep data updated.

It worked well with Vue 1.x, but after update to 2.0 sorting became incorrect. Array still properly updates, but items in DOM are in the wrong places.

new Vue({
el: '#app',
template: '#sort',
data: function() {
return {
items: [
"http://placehold.it/200X300?text=image1",
"http://placehold.it/200X300?text=image2",
"http://placehold.it/200X300?text=image3",
"http://placehold.it/200X300?text=image4"
],
}
},
mounted: function() {
this.$nextTick(function () {
Sortable.create(document.getElementById('sortable'), {
animation: 200,
onUpdate: this.reorder.bind(this),
});
})
},
methods: {
reorder: function(event) {
var oldIndex = event.oldIndex,
newIndex = event.newIndex;
this.items.splice(newIndex, 0, this.items.splice(oldIndex, 1)[0]);

}
}
});


jsFiddle
https://jsfiddle.net/4bvtofdd/4/

Can someone help me?

Answer

As it happens, Sortable keeps track of the order in sortable.toArray(), so it's pretty easy to make a computed that will give you the items in sorted order, while the original item list is unchanged.

new Vue({
  el: '#app',
  template: '#sort',
  data: {
    items: [
      "http://placehold.it/200X300?text=image1",
      "http://placehold.it/200X300?text=image2",
      "http://placehold.it/200X300?text=image3",
      "http://placehold.it/200X300?text=image4"
    ],
    order: null
  },
  computed: {
    sortedItems: function() {
      if (!this.order) {
      	return this.items;
      }
      return this.order.map((i) => this.items[i]);
    }
  },
  mounted: function() {
    this.$nextTick(() => {
      const sortable = Sortable.create(document.getElementById('sortable'), {
        animation: 200,
        onUpdate: () => { this.order = sortable.toArray(); }
      });
    })
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/Sortable/1.4.2/Sortable.min.js"></script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="//unpkg.com/vue@2.0.1/dist/vue.js"></script>
<div id='app'></div>
<template id="sort">
  <div class="container">
    <div class="row sort-wrap" id="sortable">
      <div class="col-xs-6 col-md-3 thumbnail" v-for="(item, index) in items" :data-id="index">
        <img v-bind:src="item" alt="" class="img-responsive">
      </div>
    </div>
    <div v-for="item in sortedItems">
    {{item}}
    </div>
  </div>
</template>

Comments