loading...

Draggable table row with VueJS, Vuetify and SortableJS

andynoir profile image Andrey Gaisinskii ・2 min read

TLDR At the bottom of the article you will find a link to the GitHub repo.

Prologue

Recently I have had to implement draggable rows for a vuetify table and right off the bat started searching in the docs and the webs for a solution. And came across this article written by Abhay Wawale and some other answers on StackOverflow & CodePen.

The article is great, but I was concerned about manipulating the DOM directly. As for me it is a bit hacky.

My Solution

Instead of accessing the item slot in v-data-table I decided to mess around with the body slot. Basically body slot is your <tbody> html tag and it is very nice since we need a tag prop for vuedraggable component which is a wrapper for SortableJS.

    <v-data-table>
      <template v-slot:body="props">
        <draggable
          :list="props.items"
          tag="tbody"
        >
          <!-- the row will go here -->
        </draggable>
      </template>
    </v-data-table>

Now to the rows, you just have to loop through the array of items that you pass into your v-data-table items prop. Those items will be exposed in the body slot and can be accessed as follows:

          <tr
            v-for="(item, index) in props.items"
            :key="index"
          >
            <td> {{ item.your-property-here }} </td>
          </tr>

Let's add some actual data and make our table more fancy:

    <v-data-table
      :headers="tableHeaders"
      :items="tableItems"
      :loading="loading"
      item-key="id"
      :show-select="false"
      :disable-pagination="true"
      :hide-default-footer="true"
      class="page__table"
    >
      <template v-slot:body="props">
        <draggable
          :list="props.items"
          tag="tbody"
        >
          <tr
            v-for="(user, index) in props.items"
            :key="index"
          >
            <td>
              <v-icon
                small
                class="page__grab-icon"
              >
                mdi-arrow-all
              </v-icon>
            </td>
            <td> {{ index + 1 }} </td>
            <td> {{ user.id }} </td>
            <td> {{ user.name }} </td>
            <td> {{ user.username }} </td>
            <td> {{ user.email }} </td>
            <td> {{ user.website }} </td>
            <td>
              <v-icon
                small
                @click="editUser(user.id)"
              >
                mdi-pencil
              </v-icon>
            </td>
          </tr>
        </draggable>
      </template>
    </v-data-table>

Our table will look like this and draggable rows are working!

Our table!

Thanks for reading!

Code can be found here and live preview here

Discussion

markdown guide