Search code examples
javascriptvue.jsdraggablebootstrap-vuebuefy

Draggable table with bootstrap vue


I have been looking for a way to drag and drop rows on a Bootstrap Vue table. I was able to find a working version here: Codepen

I have tried to implement this code to my own table:

Template:

<b-table  v-sortable="sortableOptions" @click="(row) => $toast.open(`Clicked ${row.item.name}`)"  :per-page="perPage" :current-page="currentPage"  striped hover :items="blis" :fields="fields" :filter="filter" :sort-by.sync="sortBy" :sort-desc.sync="sortDesc" :sort-direction="sortDirection" @filtered="onFiltered">
    <template slot="move" slot-scope="row">
        <i class="fa fa-arrows-alt"></i>
    </template>

    <template slot="actions" slot-scope="row">
        <b-btn :href="'/bli/'+row.item.id" variant="light" size="sm" @click.stop="details(cell.item,cell.index,$event.target)"><i class="fa fa-pencil"></i></b-btn>
        <b-btn variant="light" size="sm" @click.stop="details(cell.item,cell.index,$event.target)"><i class="fa fa-trash"></i></b-btn>
    </template>

    <template slot="priority" slot-scope="row">
        <input v-model="row.item.priority" @keyup.enter="row.item.focussed = false; updatePriority(row.item), $emit('update')" @blur="row.item.focussed = false" @focus="row.item.focussed = true" class="form-control" type="number" name="priority" >
    </template>
</b-table>

Script:

import Buefy from 'buefy';
Vue.use(Buefy);

const createSortable = (el, options, vnode) => {

    return Sortable.create(el, {
    ...options
    });
};

const sortable = {
    name: 'sortable',
    bind(el, binding, vnode) {
    const table = el.querySelector('table');
    table._sortable = createSortable(table.querySelector('tbody'), binding.value, vnode);
    }
};
export default {
    name: 'ExampleComponent',
    directives: { sortable },
    data() {
        let self = this;
        return {
            blis: [],
            currentPage: 1,
            perPage: 10,
            pageOptions: [ 5, 10, 15 ],
            totalRows: 0,
            sortBy: null,
            sortDesc: false,
            sortDirection: 'asc',
            sortableOptions: {
                chosenClass: 'is-selected'
            },
            filter: null,
            modalInfo: { title: 'Title', content: 'priority' },
            fields: [ 
                {
                    key: 'move',
                    sortable: true
                },
                ///...rest of the fields
            ]
    }
};

Now I have been getting this error: Error in directive sortable bind hook: "TypeError: Cannot read property 'querySelector' of null"

Why is it not able to find the <tbody> ?

Edit: https://jsfiddle.net/d7jqtkon/


Solution

  • In line const table = el.querySelector('table'); you are trying to get the table element. The var el is the table element. That is why it return null when you use querySelector

    after assigning the correct table variable the error disappears

      const table = el;    
      table._sortable = createSortable(table.querySelector("tbody"), binding.value, vnode);
    

    Link to working fiddle