2

I want to create a reactive Datatable in my Laravel + Vue.js project. I'm using datatables.js library to show my data. When I make an API call to get the data from db API returns me an array, so I want to populate that array in the datatable. But it's working weird?

Here's API call:

methods: {
    getUsers() {
        axios.get('/api/users')
            .then(response => {
                if(response.status === 200) {
                    this.users = response.data.users;
                    console.log(this.users);
                }
            })
            .catch(error => {
                console.error(error);
            });
    }
},
mounted() {                
    $('#users-datatable-responsive').DataTable();
    this.getUsers();
}

This is how I populating the data in the datatable

<tr v-for="user in users">
    <td>@{{ user.fullname }}</td>
    <td>@{{ user.phone }}</td>
    <td>@{{ user.email }}</td>
</tr>

And here's the weird result: enter image description here

Searching and other features of a datatable aren't working. What's the workaround?

Edited:

mounted() {               
    let table = $('#users-datatable-responsive').DataTable({
        language: this.dataTableOptions
    });
    this.getUsers();
    table.rows().invalidate().draw();
}

This approach didn't work for me.

  • 1
    That's because DataTables plugin does not automatically detect changes in DOM and updates its internal mapping of your data. You should force the instance to refresh, by invalidating the data and redrawing it, i.e. `table.rows().invalidate().draw();` – Terry Apr 02 '18 at 11:01
  • Possible duplicate of [How do I refresh/reload my DataTable from HTML source](https://stackoverflow.com/questions/36529662/how-do-i-refresh-reload-my-datatable-from-html-source) – Terry Apr 02 '18 at 11:01
  • @Terry please look at my editings. – Камилов Тимур Apr 02 '18 at 11:07
  • @Terry this approach didn't work for me – Камилов Тимур Apr 02 '18 at 11:07
  • Probably because you are refreshing the table before axios actually successfully fetches the data and updates Vue's data store, since axios' operations are asynchronous. – Terry Apr 02 '18 at 11:13
  • @Terry `table.rows().invalidate().draw();` I put it to the `then()` method of `axios` but it's still not working. How should I properly do that? – Камилов Тимур Apr 02 '18 at 11:17
  • See my answer: you probably need to rely on `Vue.nextTick()` also, to ensure that the DOM has been updated by VueJS before you attempt to reset the table. – Terry Apr 02 '18 at 11:20
  • Try using a watcher on 'users' to perform the invalidate and draw. – GaryMcM Apr 02 '18 at 12:05

3 Answers3

1

I was unable to get Terry's answer to work, but after a little bit of playing around found that that destroying the table before render, then rebuilding the table on the next tick does work.

...
methods: {
        drawDT() {
          $("#dt").DataTable().draw();
        },
        async refreshData() {
          this.isLoading = true;
          $("#dt").DataTable().destroy();
          try {
            let data = await fetchData();
            this.users = data.slice(0, getRandomInt(1, data.length));
            await this.$nextTick(this.drawDT);
          } catch (err) {
            console.error(err);
          } finally {
            this.isLoading = false;
          }
        }
      },
...

Full example here

GaryMcM
  • 425
  • 3
  • 9
0

As per my comments, there are two issues that are causing the problem you are seeing:

  1. DataTable plugin does not automatically updates its internal cache when you update the DOM. You will need to use its API to 'reset' the table, i.e. table.rows().invalidate().draw();
  2. Axios works asynchronously, and you should reset the table only when the promise has been resolved. This should ideally be done using a custom method to keep things abstract :)
  • In your custom method, you must wait for VueJS to finish updating the DOM, since the DOM relies on iterating through this.users to render the correct markup. Use Vue.nextTick() to call the logic that 'resets' the table.

To fix this, you can call a custom method in your app/component that handles forced refreshing of the table, i.e.:

methods: {
    getUsers() {
        axios.get('/api/users')
            .then(response => {
                if(response.status === 200) {
                    // Populate VueJS data store with received data
                    this.users = response.data.users;

                    // Call a method that manually refreshes table
                    this.forceRefreshUserDataTable();
                }
            })
            .catch(error => {
                console.error(error);
            });
    }
},
mounted() {             
    this.usersDataTable = $('#users-datatable-responsive').DataTable();
    this.getUsers();
},
methods: {
    forceRefreshUserDataTable() {
        Vue.nextTick(function () {
            this.usersDataTable.rows().invalidate().draw();
        });
    }
}
tony19
  • 125,647
  • 18
  • 229
  • 307
Terry
  • 63,248
  • 15
  • 96
  • 118
0

If it is a simple table you could use this grid table component from vue docs https://v2.vuejs.org/v2/examples/grid-component.html

tony19
  • 125,647
  • 18
  • 229
  • 307
BenB
  • 2,747
  • 3
  • 29
  • 54