Creating a searchable table in Vue 2

Vue has become one of my favourite front-end tools to create manageable, data-driven, front-end pages and modules.

One of the most useful modules for data, is representing it in tabular form, and to have that data searchable, sortable, and nicely paginated. This short article will provide a sample that will hopefully give you a good starting point to bring Vue into your project, and expand the component to your needs.

For the purposes of simplicity, I’m going to keep this article to the code, without exploring more advanced features like single-file components, webpack etc.

Getting prepared

First up, you’ll need your tools. Since this is a fairly basic tutorial, all you’ll need is a decent text/code editor, such as Atom, and of course, VueJS.

The basic page code

In case you’re planning to copy-and-paste large parts of this code, I’ve included everything you need in this basic page code, including the latest stable copy of Vue.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Vue2 Table</title>
</head>
<body>

    <div id="myApp" v-cloak>
        <table>
            <thead>
                <tr>
                    <th>Col 1</th>
                    <th>Col 2</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>Data 1</td>
                    <td>Data 2</td>
                </tr>
            </tbody>
        </table>
    </div>

    <script src="https://unpkg.com/vue"></script>
</body>
</html>

Let’s get Vue plugged in!

Now that we have a (very) basic outline of our page, and table, we can begin to plug Vue in so that we can start playing with the data and display. I’m going to assume you already have a basic understanding of Vue, and I’m going to jump straight into setting it up, without a great deal of explanation.

First up, we’re going to add a style. The v-cloak attribute that we’ve added to the main #myApp div will allow us to hide the element until it has been fully rendered by Vue.

<style>
    [v-cloak] {
        display: none;
    }
</style>

We’re now going to add the JavaScript to render the app, and add a quick bit of sample data to ensure it’s working

<script>
    var vm = new Vue({
        el: '#myApp',
        data: {
            message: 'Hello World!'
        }
    });
</script>

You’ll now want to change the content of the first td element in the tbody, to allow us to see that Vue is working, and rendering our data. Change the markup for the first column to this…

<td>{{ message }}</td>

After re-loading the page, you should now have a column that says “Hello World!” Great! We’re up and running.

Adding some real data for the table

Now that we know it’s working and rendering, we can add some sample tabular data to work with. As you probably already know, the best way to provide a lot of data to Vue, especially with things like tabular data (e.g. a list of customers), is with JSON. So replace the javascript with the code below, including our array of JSON objects, to provide a fake list of customers that we can render on the frontend, in our table.

<script>
    var vm = new Vue({
        el: '#myApp',
        data: {
            customers: [{"name":"John Doe","age":"25","nationality":"British"},{"name":"Jane Doe","age":"21","nationality":"Scottish"},{"name":"Donald Frump","age":"70","nationality":"American"}]
        }
    });
</script>

With this data, we can update our markup to display it within the table. Again, I’m going to be presumptuous and assume you already know the basics of if statements and for loops. If not, I will explain a bit about what’s going on, but I’d recommend taking a look at the Vue documentation, which can explain it far better than I.

<div id="myApp" v-cloak>
    <table>
        <thead>
            <tr>
                <th>Name</th>
                <th>Age</th>
                <th>Nationality</th>
            </tr>
        </thead>
        <tbody>
            <tr v-for="customer in customers">
                <td>{{ customer.name }}</td>
                <td>{{ customer.age }}</td>
                <td>{{ customer.nationality }}</td>
            </tr>
        </tbody>
    </table>
</div>

As you can see, I’ve hard-coded the table column headings. We can (and should) make these dynamic, to make it more manageable, but since this is only an example, I’m taking the easy road, as there are more important things to look at, and it works in the same way as the body of the table.

What’s going on in that code!?

You can see I’ve added a v-for loop on the tr element. This means that Vue will add a table row for each row in the customers array. The row will be assigned to the an object called customer, which we can then drill down to the individual columns/data.

I’ve then added a td element for each column of data, and within that added the Vue code to output the data I want.

When you reload this page on the frontend, you should now see three rows in your table, with the data for each of the three people (yes, Frump was intentional).

Let’s make the data searchable!

Okay, we now have a working app with a table that is using our data! We can now easily swap out that array of JSON objects to data we’ve pulled from a database, but as this is a basic tutorial focussing on creating the table component, I’m going to skip that part and move on to making the data searchable.

First, let’s add an input into the page and assign it, via a vue model, to a data variable.

<div id="myApp" v-cloak>
    <input type="text" name="q" v-model="searchQuery" />
    <table>
<script>
    var vm = new Vue({
        el: '#myApp',
        data: {
            customers: [{"name":"John Doe","age":"25","nationality":"British"},{"name":"Jane Doe","age":"21","nationality":"Scottish"},{"name":"Donald Frump","age":"70","nationality":"American"}],
            searchQuery: ''
        }
    });
</script>

Now we’ve set that up, we need to search our data for the query provided. This is actually very straight forward, all we need to do is filter the existing object (customers), and feed back a new object, containing the results, back to our table. We’re going to do this using a computed property.

var vm = new Vue({
    el: '#myApp',
    data: {
        customers: [{"name":"John Doe","age":"25","nationality":"British"},{"name":"Jane Doe","age":"21","nationality":"Scottish"},{"name":"Donald Frump","age":"70","nationality":"American"}],
        searchQuery: ''
    },
    computed: {
        customerList: function() {
            return this.customers.filter(item => {
                if (!this.searchQuery) {
                    // If there's no search term, return the item immediately
                    return item;
                } else {
                    // Otherwise, only return the item if we have a match
                    return (
                        item.name.toLowerCase().indexOf(this.searchQuery.toLowerCase()) > -1 ||
                        item.age.indexOf(this.searchQuery) > -1 ||
                        item.nationality.indexOf(this.searchQuery) > -1
                    );
                }
            })
        }
    }
});

If you now reload the page, and try to use the search input, you’ll notice nothing happens, that’s because we’re still output the unfiltered customers object to the table, so let’s change that to use the new filtered customerList object.

<tbody>
    <tr v-for="customer in customerList">
        <td>{{ customer.name }}</td>
        <td>{{ customer.age }}</td>
        <td>{{ customer.nationality }}</td>
    </tr>
</tbody>

Now, reload the webpage in your browser, and type something into the input field. You should notice it’s now filtering the table results, and only showing you items matching your search term. You can easily customise this to search any and all fields in the base object (i.e. you could remove nationality to only search by name and age).

Hopefully you’ve found this easy to follow, and get started with. In the next article, I’ll be explaining how to sort, and paginate these results, to provide your data in smaller, more manageable chunks.

Find the full code on GitHub at https://github.com/mattgibbo/vue2-table/.

Leave a Reply