Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

willvincent's avatar

Using DataTables with Vue

I spent far too many hours fighting with DataTables the past couple of days, so I thought I would share how I worked out a reliable way to work with it alongside/within Vue.

Firstly, you obviously need to add all of the appropriate DataTables JS and CSS to the page, I'm going to assume you can manage that bit. (See the note about browserify issues at the bottom of this post)

Now, lets take a look at a pretty simple Vue component that will work with DataTables and allow you to dynamically update the data. For my purposes I wanted to have a fixed header and sidebar, which is really what drove me to datatables in the first place. The number of columns and rows being displayed in these tables on the site I'm working on is so vast that having fixed header and columns is essential to be able to navigate it.

<template>
  <table id="table-id" class="whatever-classes-you-need not-much-to-this-template"></table>
</template>

<script>
  export default {
    props: ['tableData'],
    data() {
      return {
        headers: [
          { title: 'Define' },
          { title: 'Your', class: 'some-special-class' },
          { title: 'Column Names' },
          { title: 'Here' }
        ],
        rows: [] ,
        dtHandle: null
      }
    },
    watch: {
      tableData(val, oldVal) {
        let vm = this;
        let rows = [];
        // You should _probably_ check that this is changed data... but we'll skip that for this example.
        val.forEach(function (item) {
          // Fish out the specific column data for each item in your data set and push it to the appropriate place.
          // Basically we're just building a multi-dimensional array here. If the data is _already_ in the right format you could
          // skip this loop...
          let row = [];

          row.push(item.some_thing);
          row.push(item.some_other_thing);
          row.push(item.another_thing);
          row.push(item.final_thing);

          vm.rows.push(row);
        });

        // Here's the magic to keeping the DataTable in sync.
        // It must be cleared, new rows added, then redrawn!
        vm.dtHandle.clear();
        vm.dtHandle.rows.add(vm.rows);
        vm.dtHandle.draw();
      }
    },
    ready() {
      // Instantiate the datatable and store the reference to the instance in our dtHandle element.
      this.dtHandle = $(this.$el).DataTable({
        // Specify whatever options you want, at a minimum these:
        columns: this.headers,
        data: this.rows
      });
    }
  }
</script>

So, DataTables is a little bit tricky to deal with, but if you want to be able to dynamically change it's data with Vue (without relying on DataTables' ajax functionality) you need to pass data to it via javascript, not try to latch onto a rendered table in the dom. The DataTables object can only be configured once, further updates have to reference the handle we define.. It takes a little doing, but in the end you can have a very dynamic table whose contents are controlled by one or several outside filters.

In my case I have 6 separate filters that could be applied at any given time to my dataset (one of which is a text search), and the data updates instantly.. the only requirement is that you pass in the filtered data to the component.

I do that by passing a computed value to it, and that computed value applies all of the applicable filters thusly:

computed: {
  filteredProjects() {
      let projects = this.projects;
      let program_id = this.currentProgram;
      let order = this['sortBy'];

      projects = this.$options.filters.orderBy(
        this.$options.filters.filterBy(
          this.$options.filters.projectFilters(
            this.$options.filters.filterBy(projects, program_id, 'program_id'
            ), this.filters
          ), this.filters.searchQuery
        ), order);

      return projects;
  }
}

Obviously the orderby isn't necessary since datatables is perfectly capable of handling sort order, but I have a different non-table view of the same data on the same page, so that I can toggle between a block and table view of the data. In the case of the block data it's ordered by a value selected in a dropdown, and optionally paginated, so I just v-for="project in filteredProjects | limitBy limit offset" for that. No sense in running the data through all the same filters in several places, and it looks a bit cleaner in the markup, to my eye, by not passing it through several filters..

You could copy/paste the above to a my-table.vue to use with vueify and it should work without any significant issues.

Of note: the datatables libraries do not seem to play very nicely with browserify, so you might want to just go ahead and skip that to avoid some headache... if you do want to try it that way, you'll need to do something like this:

window.DataTables = require('datatables.net')();

if you skip the () at the end of that line it won't work at all. I opted to manually concatenate a bunch of related libs outside of browserify because I could not for the life of me get the datatables buttons extension to work via browserify at all...

My datatables config (in the ready function) looks like this:

this.dtHandle = $(this.$el).DataTable({
        columns: this.headers,
        data: this.rows,
        searching: false,
        paging: false,
        fixedHeader: true,
        fixedColumns: true,
        scrollY: scrollY + 'px',
        scrollX: true,
        info: false,
        buttons: [
          {
            extend: 'colvis',
            collectionLayout: 'fixed two-column',
            text: 'Show/Hide Data'
          },
          {
            extend: 'csv',
            text: 'Export CSV'
          },
          {
            extend: 'excel',
            text: 'Export Excel'
          }
        ]
      });

      this.dtHandle.buttons().container().appendTo('#table-id_wrapper');

This fixes the header, left column, and includes buttons to toggle column visibilty and export to csv or excel... and then appends the buttons to the table wrapper (so they appear after the table), you could also prepend to put the buttons above the table. As for the scrollY: scrollY + 'px', line.. I calculate the height of the table, based on where the top of it lands on the page so that it fills the screen, or is at least 300px tall:

let scrollY = (Math.floor(window.innerHeight - this.$el.getBoundingClientRect().top) - 140);
if (scrollY < 300) {
  scrollY = 300;
}

That immediately preceeds the this.dtHandle line in my ready() function.

Anyway, hope this helps someone avoid the pain in the rear I dealt with getting this working!

0 likes
22 replies
willvincent's avatar

Nah.. MAD scientist maybe...

Mad Scientist

Although, considering I've not even really looked at Vue at all before 2 or 3 days ago -- let alone used it.. I'm pretty happy with my progress. It really is easy to learn. I'm digging it.

4 likes
jimmck's avatar

@willvincent Thank You!!!! I was gathering info on this specifically. This is a most useful Brain Dump! Did I say Thank You!

1 like
willvincent's avatar

@jimmck Excellent, my work is done here. :)

I realized a few minutes after posting this that I should have done so on my woefully neglected blog.. So I posted a similar thing there.

4 likes
jekinney's avatar

@willvincent

How is your set up performance work with thousands of rows? Always broke down for me and the data tables docs mention server side stuff. Which I attempted once long time ago. But remember it was frustrating as heck.

I assume your code should fix that as you are reloading data from vue methods?

willvincent's avatar

Should be fine yeah.. you could do pagination with vue, so that datatables would only ever be handling the data currently being displayed. The caveat there though would be that if you were doing pagination outside of datatables, you'd need to handle column sorting outside of datatables too otherwise the table header sort order would only affect the rows being displayed.

roulendz's avatar

New to all Vue world,

Can not figure, how to pass data to table with ajax request

willvincent's avatar

Can you not see the code in the original post? What other code are you hoping for?

craigg75's avatar

The reason OneWayTech vue2-datatable doesn't compare is because you must define the width of the columns ahead of time. Where as Datatables.net auto adjusts the width to the contents. This is a must when you are spanning the entire screen. This is also the meanest part of the code in DataTables.net. I looked at it and it's crazy but it works magically. It's unfortunate that there really isn't a quality datatable in vue currently. I'm too much of a noob to break into vue2-datatable and add the necessary parts that it needs.

paultechguy's avatar

Thanks; good info.

I also have been integrating with DataTables. The main issue I have is I have a cell when I create the table (via v-for) that I have an v-on:click handler. When I manually add a row in the DataTable (via an add button), there doesn't appear to be any way to add my cell...and have the click handler work.

Any ideas?

testlara's avatar

Sir , I want to build a share with whatsapp link of a product in mobile end api ..The problem is what would be the link ? api service link is separate to web end ..if a user got link in mobile end if he installed the app is ok ...but if he hits with url a jeson file would show ,which is bad ..How to solve it ..Please help me ..For information that projectt is no front end for web end ,but has front end in mobile end ..Web end has only admin panel ...So please solve it ...

Alpha0_0's avatar

@willvincent Thanks for solution. I have solved datatable issue with this solution in my vuex module but i want to implement vue draggable along with datatable. So i can't figure out how to. Can anyone has done ??

Please or to participate in this conversation.