admin管理员组

文章数量:1336321

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: /

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/d7jqtkon/

Share Improve this question edited Apr 23, 2020 at 11:32 Ari asked Feb 13, 2019 at 12:53 AriAri 4171 gold badge6 silver badges25 bronze badges 2
  • Can you create a fiddle or pen for your case ? may be queySelector is unable to read because tbody is not available try to add the code within document.addEventListener('DOMContentLoaded',function(){ }); – karthickj25 Commented Feb 13, 2019 at 13:32
  • I am getting the same error jsfiddle/d7jqtkon @karthickj25 – Ari Commented Feb 13, 2019 at 14:04
Add a ment  | 

2 Answers 2

Reset to default 3

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

new Vue({
  el: "#app",
    directives: {
    sortable: {
      bind(el, binding, vnode) {
        let self =el
        Sortable.create(el.querySelector('tbody'),{
          ...binding.value,
          vnode:vnode,
          onEnd: (e) =>  {
            let ids = el.querySelectorAll("span[id^=paper_]")
            let order = []
            for (let i = 0; i < ids.length; i++) {
              let item = JSON.parse(ids[i].getAttribute('values'))
              //extract items checkbox onChange v-model
              let itemInThisData = vnode.context.items.filter(i => i.id==item.id)
              order.push({
                id:item.id,
                paper: item.paper,
                domain:item.domain,
                platform: item.platform,
                country:item.country,
                sort_priority: item.sort_priority,
                selectpaper:itemInThisData[0].selectpaper
              })
            }
            binding.value = []
            vnode.context.items = []
            binding.value = order
            vnode.context.items = order
            console.table(vnode.context.items)
          },
        });
      },    
    }
  },
  mounted() {
    this.totalRows = this.items?this.items.length: 0
  },
  methods:{
    onFiltered(filteredItems) {
      // Trigger pagination to update the number of buttons/pages due to filtering
      this.totalRows = filteredItems.length
      this.currentPage = 1
    },
    log(){
      console.table(this.items)
      console.log(this)
    },
  },
  data(){
    return {
    rankOption:'default',
    totalRows: 1,
    currentPage: 1,
    filter: null,
    filterOn:[],
    sortBy:'paper',
    sortDesc: false,
    sortableOptions: {
      chosenClass: 'is-selected'
    },
    perPage: this.results_per_page==='Todo' ? this.items.length : this.results_per_page?this.results_per_page:50,
    pageOptions: [10, 50, 100, 500,'Todo'],
    sortDirection: 'asc',
    fields : [
      { key: 'paper', label: 'Soporte', sortable: true},
      { key: 'domain', label: 'Dominio', sortable: true},
      { key: 'platform', label: 'Medio', sortable: true},
      { key: 'country', label: 'País', sortable: true},
      { key: 'sort_priority', label: 'Rank', sortable: true},
      { key: 'selectpaper', label: 'Selección', sortable: true},
    ],
    items : [
      {
        id:12,
        paper: 'Expansion',
        domain:'expansion.',
        platform: 'p',
        country:'España',
        sort_priority: '',
        selectpaper:false
      },
      {
        id:13,
        paper: 'El economista',
        domain:'eleconomista.es',
        platform: 'p',
        country:'España',
        sort_priority: '',
        selectpaper:false
      },
      {
        id:14,
        paper: 'El país',
        domain:'elpais.es',
        platform: 'p',
        country:'España',
        sort_priority: '',
        selectpaper:false
      }
    ]
  }
    }
})
<div id="app">
<template id="">
  <b-table
  :sort-by.sync="sortBy"
  :sort-desc.sync="sortDesc"
  v-sortable="items"
  show-empty
  small
  stacked="md"
  :items="items"
  :fields="fields"
  :current-page="currentPage"
  :per-page="perPage"
  :filter="filter"
  :filterIncludedFields="filterOn"
  :sort-direction="sortDirection"
  @filtered="onFiltered"
  >
  <template v-slot:cell(selectpaper)="row">
    <span :id="'paper_'+row.item.id" :values="JSON.stringify(row.item)"></span>
    <b-form-group>
      <input  type="checkbox" @change="log" v-model="row.item.selectpaper" />
    </b-form-group>
  </template>
  <template v-slot:cell(sort_priority)="row" v-if="rankOption==='foreach-row'">
    <b-form-group>
      <b-form-input type="number"  @change="log"
      size="sm" placeholder="Rank" v-model="row.item.sort_priority">
    </b-form-input>
  </b-form-group>
  </template>
  </b-table>
</template>
</div>
<script src="//unpkg./vue@latest/dist/vue.min.js"></script>
<script src="//unpkg./bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="https://cdn.jsdelivr/npm/sortablejs@latest/Sortable.min.js"></script>

本文标签: javascriptDraggable table with bootstrap vueStack Overflow