Blogs, E-commerce sites, admins, and search results, almost everywhere you go online you are presented with large amounts of data and results, this transfer of information is a big part of what web applications are about.
In this article we are going to take a look at how you can make your application dynamic by allowing your users to sort and navigate the data you are showing them using Vue.js.
The Game Plan
We are going to be building a reactive table like in the picture above, but before we get down to the build, I find it helpful to break down the problem into smaller more specific tasks or features.
- We want to be able to sort our table by column.
- We want to be able to paginate our data.
Leaning on the reactivity of Vue.js you will see how easy it is to make a reusable table that adapts to the data you provide it. So without further ado, let’s get right into it.
Displaying the Data in a Table
First things first, before we can start making the table dynamic, we need to create the table itself. The data we will be using is a list of users with the columns: id, name, phone, and profession. The simplest way to render our data using Vue.js is by using the v-for directive to iterate an HTML template over a list.
The main problem with the above code is that it is tightly bound to the specific data we used. If the data changes you will need to update the template along with it. We can take this one step further and define the columns in the data field of our component, or better yet, if your data all follows the same format, you can let Vue.js read the keys itself (how meta of us).
Iterating over the columns is exactly like how we iterated over the rows in the previous example, and now when we iterate over the rows, for each row we iterate on all its columns.
By using v-for inside a v-for we not only shortened our template significantly but made our Vue.js table a more lot adaptable to any data you throw at it. It is generally a good idea to remove any tightly bound links between your data and template when building something where the data can change.
Sorting Our Table
Sorting the table is a lot simpler than you may think. Traditionally, this involves sorting the data itself and then re-rendering the HTML, all the while keeping track of click events on the columns and sorting direction. Vue.js takes care of a lot of it for us—by just updating the underlying array of users, the table will react automatically.
Let’s start simple and just have the data sort itself when clicking on a column. To do this we need to add a click event to the column’s headers which when clicked will sort the data accordingly.
We add the click event handler by using the v-on:click directive in our template on each <th> element that calls a method called sortTable, passing the column with which to sort the data.
Now playing with the table, you can see this is pretty cool, but only sorts in one direction. To sort in the other direction, the closure we pass to the sort method needs to return 1 where we returned -1and visa versa, essentially flipping the order.
To accomplish this we need to keep track of which column we are currently sorting by, and in which direction to sort – ascending or descending. So let’s go ahead and add these two fields to our dataobject and update the sort method.
Bi-directional sorting, now we are getting somewhere; we have already implemented all the logic needed to sort the table, but it would be nice to be able to have some indication as to what is being sorted, and how.
If you think about it logically, what we want to do is add something to indicate whether we are sorting in ascending or descending order to a column, if we are currently sorting by that column. Vue.js has a built in directive v-if that accepts an expression and only adds the HTML element to the page if the expression is evaluated true.
So we add an element to the th element for the column which is currently being sorted, and then we give our indicator element the class arrow_up or arrow_down based on the ascending field in our Vue.js component using another directive v-bind.
The v-bind directive allows you to reactively bind a value to any attribute or property of an HTML element. For example you can use v-bind:href to bind a url dynamically to an element. The advantage to using v-bind is that whenever the underlying data used in the expression is changed the attribute will be automatically updated.
Paginating Our Data
In terms of HTML, or the sorting functionality we just added, displaying a paginated table is no different than displaying a full table. The only real difference is you only want to display a subset of the array of data. The question is, just how do you want to split up your data?
If you know what page you are currently on and you know how many results you want to display per page, you can take a slice out of the full array and iterate over it instead of iterating directly over all rows. So let’s add these two properties as fields in our component, and instead of iterating over rows like we have been doing we will add a method which returns a subset of the data, based on those properties.
In order to display the page numbers we also added a method which calculates the number of pages there will be in total, and we use v-for again to iterate through all the pages. When specifying a number to v-for instead of an array, Vue.js will create a loop which will count from 1 up to (and including) the number you specified.
Changing pages is as simple as updating the field we added which stores the current page. We don’t need to worry about re-sorting or re-rendering the page, or even re-splitting the array into a new sub-array. If the method used to return a subset of the array uses the property currentPage, then just by updating the value, everything will update automatically.
In this article we built a data-table using some basic directives in Vue.js. But it’s worth noting that the only thing making this a table is the HTML template. Everything we did here would work on a blog, grid layout, or really any other HTML representation all the same.
Moving forward there are many more features you can add to this; the same concepts used to paginate, where we iterate over a subset of the data, can be used to add filtering your table with a search box, or you can asynchronously load your data one page at a time, and by replacing the rows property, achieve a lazily loaded data table.