Vue Draggable Second List Does Not Keep Sort

2.6k Views Asked by At

I receive a list of new orders and display them vertically in column A. There is a second column, B, that shows a current prioritized list ordered how individuals want. When I drag an item from column A to column B, it does move the item, which is good. However, it previews correctly but when dropped, the new item ALWAYS goes to the bottom of column B.

I am using this component to get me the drag and drop functionality.

Here is a an example/proof of what I am talking about.

Even once items are in column B and I want to drag and drop them within that column, they preview fine but do not stay when the mouse button is released.

I can fix this inner-sorting issue with the following code (although I believe this should be what the code does without me making changes.):

On the draggable add the following event handler:

v-on:end="end"

And in the JS code, catch the event:

end(e) {
  this.prioritizedNewOrders.splice(e.newIndex, 0, this.prioritizedNewOrders.splice(e.oldIndex, 1)[0]);
}

That still does not fix the initial drag into column B though.

ANSWER @sphinx's answer is correct! Here is an updated fiddle with the answer.

1

There are 1 best solutions below

0
On BEST ANSWER

Look into Vue-draggable: slot,

Use the footer slot to add none-draggable element inside the vuedraggable component.

Important: it should be used in conjunction with draggable option to tag draggable element. Note that footer slot will always be added after the default slot.

So add slot="footer" and put it after the default slot, then works fine.

Vue.config.productionTip = false
new Vue({
  el: "#app",
  data: {
    todos: [
      { id: 1, text: "Learn JavaScript", done: false },
      { id: 2, text: "Learn Vue", done: false },
      { id: 3, text: "Play around in JSFiddle", done: true },
      { id: 4, text: "Build something awesome", done: true }
    ],
    newTodos: []
  },
  methods: {

  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<!-- CDNJS :: Sortable (https://cdnjs.com/) -->
<script src="//cdn.jsdelivr.net/npm/[email protected]/Sortable.min.js"></script>

<!-- CDNJS :: Vue.Draggable (https://cdnjs.com/) -->
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.16.0/vuedraggable.min.js"></script>

<!-- CDNJS :: Sortable (https://cdnjs.com/) -->
<script src="//cdn.jsdelivr.net/npm/[email protected]/Sortable.min.js"></script>

<!-- CDNJS :: Vue.Draggable (https://cdnjs.com/) -->
<script src="//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.16.0/vuedraggable.min.js"></script>

<div id="app">

<p><i>Drag things from the "New Orders" list to the "Prioritized Orders" list. You will see that they sort fine while they are in the New Orders list.  But when you drag them to be a certain location (not the last spot) on the Prioritized Order list, they ALWAYS jump to the bottom.  Even though you can "See" that they will show up where you want them until you let go of the mouse.</i></p><br />
<p>
<i>Also, sorting works great in the New Orders list.  But once items are in the Prioritized list, they show that it will look good until you let go of the mouse.</i>
<br /><br />Adding this code to the "end" event will fix the sorting.  But IMHO, this should work without ME coding anything:<br /><br />
<div style="font-family: 'courier-new'">
this.prioritizedNewOrders.splice(e.newIndex, 0, this.prioritizedNewOrders.splice(e.oldIndex, 1)[0]);
</div>
</p><br />
<!-- New Items -->
<div class="d-flex justify-content-between">
 <b>New Orders - Not yet Prioritized</b>
 <label>{{ todos.length }}</label>
</div>

<draggable v-model="todos"
      v-bind:options="{ group: { name: 'Orders', pull: true } }">
 <div style="border: 1px solid #ccc; margin-bottom: 3px;"
    v-for="o in todos"
    v-bind:key="o.id">
  <div style="padding: 1rem;">
   <label>{{ o.text }}</label><br />
   <label>{{ o.done }}</label>
  </div>
 </div>
</draggable>

<!-- Ordered Queue -->
<br />
<div>
 <b>Prioritized Orders Queue</b>
 <label>{{ newTodos.length }}</label>
</div>

<div class="prioritized-new-orders" style="border: 1px solid #ccc; background-color: #eee;">
 <draggable v-model="newTodos"
       v-bind:options="{ group: { name: 'Orders', put: true }, animation: 250 }">
  <div style="border: 1px solid #ccc; margin-bottom: 3px;"
     v-for="o in newTodos"
     v-bind:key="o.id">
   <div style="padding: 1rem;">
    <label>{{ o.text }}</label><br />
    <label>{{ o.done }}</label>
   </div>
  </div>
  <p slot="footer" class="text-info p-3 mb-0" v-if="newTodos.length === 0">Drag and Drop New Orders from the left column here to Prioritize them.</p>
 </draggable>
</div>

</div>