Léna Santamaria
Léna Santamaria

Reputation: 41

How to use vue-draggable (or Sortable JS) in a v-data-table with Vuetify 2 and Vue JS 2?

I'm trying to use vue-draggable with Vuetify v-data-table by following this article : https://medium.com/vuetify/drag-n-drop-in-vuetify-part-ii-2b07b4b27684

It says : "The main goal was to set tbody of table as draggable component and it was not possible because Vuetify uses template as a slot for rendering items."

After that, the guy found a solution with Sortable JS. I tried it but it's not working.

this error appears : Sortable: el must be an HTMLElement, not [object Function].

People are saying that Sortable JS is not working for Vue JS 2...

How can I do ?

If you have a solution please let me know :)

My code :

    <v-data-table
      :headers="headers"
      :items="slots"
      :items-per-page="-1"
      ref="sortableTable"
    >
      <template v-slot:item="props">
        <tr v-if="props.item.recipe" class="sortableRow">
          <td style="text-align: center">{{props.item.slot}}</td>
          <td style="text-align: center" v-if="props.item.recipe.preferences">
            <v-chip
            v-for="pref in props.item.recipe.preferences"
            :key="pref"
            small
          >
            {{ pref }}
          </v-chip>
          </td>
          <td style="text-align: center">{{props.item.recipe.protein}}</td>
          <td style="text-align: center">{{props.item.recipe.protein_cut}}</td>
          <td style="text-align: center">{{props.item.recipe.carb}}</td>
          <td style="text-align: center" v-if="props.item.recipe.tags">
            <v-chip
              v-if="props.item.recipe.tags.indexOf('c3_appropriate') !== -1"
              small
              color="success"
              text-color="white"
            >
              C3
            </v-chip>
          </td>
          <td style="text-align: center">{{props.item.recipe.ready_in}}</td>
          <td style="text-align: center">
            <v-chip
              small
              :color="props.item.recipe.new_repeat === 'repeat' ? 'error' : 'success'"
            >
              {{ props.item.recipe.new_repeat }}
            </v-chip>
          </td>
          <td style="text-align: center">
            {{ props.item.recipe.title + ' ' }}
            <span
              v-if="props.item.recipe.subtitle"
              style="font-size: 11px"
            >
                <br>
                {{ props.item.recipe.subtitle }}
              </span>
          </td>
        </tr>
        <tr v-else>
          <td style="text-align: center">{{props.item.slot}}</td>
        </tr>

      </template>
    </v-data-table>


mounted() {

        let table = document.querySelector("table tbody");
        console.log(table)
        const _self = this;
        Sortable.create(table, {
            draggable: '.sortableRow',
            handle: ".handle",
            onEnd({newIndex, oldIndex}) {
                const rowSelected = _self.slots.splice(oldIndex,1)[0];
                _self.slots.splice(newIndex, 0, rowSelected);
            }
        });
    }

Upvotes: 4

Views: 3629

Answers (1)

erny
erny

Reputation: 2509

I'm using SortableJS with Nuxt. The shortest solution I found was to register a directive with Vue.directive:

import Vue from 'vue'
import {Sortable} from 'sortablejs';
Vue.directive("sortableDataTable", {
  bind(el, binding, vnode) {
    const options = {
      animation: 150,
      onUpdate(event) {
        vnode.child.$emit('sorted', event)
      }
    }
    Sortable.create(el.getElementsByTagName('tbody')[0], options)
  }
})

Now I can use the v-sortable-data-table directive in a v-data-table:

  <v-data-table
    v-sortable-data-table
    :items="items"
    :headers="headers"
    item-key="id"
  >
  </v-data-table>

Note that the directive is registered as sortableDataTable but is used as v-sortable-data-table (camelCase is converted to kebab-case and must be prefixed with 'v-' when used).

Upvotes: 3

Related Questions