Vue.js + Sortable TaskApp

Goal: Sort and update position through AJAX

by sutherland

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.16/vue.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.4.2/Sortable.min.js"></script>
<div id="app">
  <h1>{{ title | uppercase }}</h1>
  <div id="task-row" v-sortable.ul="tasks">
    <ul class="row col-xs-12" v-for="task in tasks" track-by="$index">
      <div class="box btn-reorder col-xs-1">&#9776;</div>
      <div class="box col-xs-1">{{ $index + 1 }}</div>
      <div class="box col-xs-4">{{ task.description }}</div>
      <div class="box col-xs-3">task.position:
        <input class="hidden" v-model="task.position" value="{{ $index + 1 }}">{{ task.position }}</div>
    </ul>
  </div>
</div>

CSS

body {
  font-family: Helvetica Neue, Arial, sans-serif;
}

.box {
  height: 30px;
  width: auto;
  border: 1px solid grey;
  padding-top: 4px;
  margin: 5px 5px;
}

.btn-reorder {
  font-size: 22px;
  padding: 0 5px;
  margin-right: 2px;
  cursor: pointer;
}

.sortable-ghost {
  background: rgba(0, 0, 0, 0.1);
  border: 2px dashed $dark-grey;
}

JavaScript

Vue.directive('sortable', {
  twoWay: true,
  deep: true,
  bind: function() {
    var that = this;

    var options = {
      draggable: Object.keys(this.modifiers)[0],
      ghostClass: "sortable-ghost", // Class name for the drop placeholder
    };

    this.sortable = Sortable.create(this.el, options);
    console.log('sortable bound!')

    this.sortable.option("onUpdate", function(e) {
      console.log("update-1");
      that.value.splice(e.newIndex, 0, that.value.splice(e.oldIndex, 1)[0]);
      that.value.forEach(function(task, index) {
        task.position = index + 1;
      });
    });

    this.onUpdate = function(value) {
      console.log("update-3");
      that.value = value;
    }
  },
  update: function(value) {
    console.log("update-2");
    console.log(value);
    this.onUpdate(value);
  }
});

var app = new Vue({
  el: '#app',
  data: {
    title: 'Tasks',
    tasks: [{
      description: 'One task',
      position: '1'
    }, {
      description: 'Another task',
      position: '2'
    }, {
      description: 'A third task',
      position: '2'
    }]
  }
})