Search code examples
javascriptvue.jsdrag-and-dropvuejs2rubaxa-sortable

Rubaxa-Sortable Failed to execute 'matches' on 'Element': '>*' is not a valid selector


I am using vuejs and Rubaxa Sortable JavaScript library. The sortable is working fine with <ul><li> but with table-rows, it's giving this error when I rearrange by drag-and-drop.

Sortable.min.js:3 Uncaught DOMException: Failed to execute 'matches' on 'Element': '>*' is not a valid selector.

I am using Vue.js v2.5.13 and Rubaxa Sortable v1.7.0.

Vue.directive('sortable', {
  inserted: function (el, binding) {
    var sortable = new Sortable(el, binding.value || {});
  }
});
new Vue({
  el: '#app',
  data () {
    return {
      items: [{id: 1},{id: 2},{id: 3},{id: 4},{id: 5}]
    }
  },
  methods: {
    reorder ({oldIndex, newIndex}) {
      const movedItem = this.items.splice(oldIndex, 1)[0]
      this.items.splice(newIndex, 0, movedItem)
    }
  }
})
<script src="https://vuejs.org/js/vue.min.js"></script>
<script src="https://cdn.rawgit.com/RubaXa/Sortable/c35043730c22ec173bac595346eb173851aece20/Sortable.min.js"></script>
<div id="app">
  <h2>With List</h2>
  <ul v-sortable="{onEnd: reorder}">
    <li v-for="i in items" :key="i.id">{{ i.id }}</li>
  </ul>

  <hr/>

  <h2>With Table</h2>
  <table v-sortable="{onEnd: reorder}">
    <tr v-for="i in items" :key="i.id">
      <td>{{ i.id }}</td>
    </tr>
  </table>

  {{ items }}

</div>


Solution

  • A <table> cannot contain table rows (<tr>). The structure of a table is like this.

    <table>
       <thead></thead>
       <tbody></tbody>
       <tfoot></tfoot>
    </table>
    

    So when we write html table like this,

    <table>
       <tr>First Row</tr>
       <tr>Second Row</tr>
    </table>
    

    The browser automatically inserts all rows inside <tbody> and renders it like this.

    <table>
       <tbody>
          <tr>First Row</tr>
          <tr>Second Row</tr>
       </tbody>
    </table>
    

    So table rows are not direct child of <table>, rather they are children of <tbody>. So generate your table rows inside <tbody> and add v-sortable to that <tbody>.

    <table>
       <tbody v-sortable="{onEnd: reorder}">  <!-- v-sortable here -->
          <tr v-for="i in items" :key="i.id">
             <td>{{ i.id }}</td>
          </tr>
       </tbody>
    </table>
    

    And the minified version of Sortable has a bug, they somehow got rid of a try-catch block when the minified it causing it to fail when anything other than <ul><li> is sorted. So untill they fix it, use the development i.e uncompressed version of Sortable.