Click Event Filtering on a JSON Rendered List in Vue.js
Tags: javascript, vue, frontend, beginners
Published: 2018-12-04 17:54:11

---
title: Click Event Filtering on a JSON Rendered List in Vue.js
published: true
description: In this tutorial, we fetch a JSON file, build a list from the data, and filter the list with click event controls.
tags: Javascript, Vue, frontend, beginners
cover_image: http://www.alexmourer.com/wp-content/uploads/2018/12/Ellis-Park-7-28-2-of-1.jpg
---

In this tutorial, we'll explore basic click event filtering on a rendered list using JSON data in [Vue.js](https://vuejs.org/). This is a basic tutorial, but it should be a solid foundation to start building something more complex.

**TL;DR**
Here is an example of a working CodeSandbox
https://codesandbox.io/s/kkvr7z5rr3
![working-example](https://thepracticaldev.s3.amazonaws.com/i/xl455y4r4u3acdki28yg.gif "working example")

####Why would we need to do this?
Filtering data is a part of my everyday life as a front-end dev. I'm often presented with a large piece of data that needs to be looped through, filtered, and displayed. In this tutorial, we will `fetch()` a [JSON file](https://next.json-generator.com/api/json/get/4JCnNiTCr), build a rendered list from the data, and filter the list with click event controls.  

We will not be using any dependencies outside of Vue.js.

####How do we do this?
First, we'll need to have Vue.js up and running. This is covered [here](https://vuejs.org/v2/guide/), or you can set up a [CodeSandbox](https://codesandbox.io).


If you used the Vue CLI or CodeSandbox to set up your app, you'll likely already have the initial structure of your project in place. In case you don't, you'll need a place to display our future component.


```html
// App.vue file
<template>
  <div id="app">
  </div>
</template>
<script>
  export default {
    name: "App"
  }
</script>
```
The above code is a good starting point for this tutorial. In the provided [CodeSandbox example](https://codesandbox.io/s/kkvr7z5rr3), **this file is named `App.vue`**. The code shown here will serve as the foundation for displaying the component we will build.

**In this tutorial, we will be placing the filter controls and rendered list inside the same component.** If this were a larger application or a longer tutorial, I would likely split them in two and share data between. I've written a separate tutorial on sharing data between multiple components [here](https://dev.to/alexmourer/sharing-data-between-components-invuejs-48me).


####Okay, let's start building out our component. 

In the provided [example](https://codesandbox.io/s/kkvr7z5rr3) the file we are working with is named **DataDisplay.vue**.

```html
// DataDisplay.vue file
<template>
  <div>
  </div>
</template>

<script>
  export default {
    name: "DataDisplay"
  };
</script>
```
The first thing we'll work on is data. I've created sample JSON data through a service called [JSON Generator](https://next.json-generator.com/). To bring the data into our `DataDisplay.vue` file, we'll `fetch()` the data in the `created` lifecycle hook. Information on lifecycle hooks can be found [here](https://vuejs.org/v2/guide/instance.html#Instance-Lifecycle-Hooks). All of the data returned will be stored in the data property `users`.

```html
// DataDisplay.vue file
<template>
  <div>
  </div>
</template>

<script>
  export default {
    name: "DataDisplay"
    data: function() {
      return {
        users: []
      }
    },
    created() {
      var apiURL = "https://next.json-generator.com/api/json/get/4JCnNiTCr";
      fetch(apiURL)
        .then(res => res.json())
        .then(res => (this.users = res))
        .catch(error => console.log(error));
    }
  }
</script>
```
**Now that we have our data stored, we can work on displaying it.**

Let's loop through the data stored in the `users` property with Vue's `v-for` directive. The [v-for directive](https://vuejs.org/v2/guide/list.html) requires a syntax structure of `x in y` or `(x, i) in y`. You can also use `of` as the delimiter instead of `in`. In this example, our syntax is `"(entry, index) in users"`, where `users` is the data source, `entry` is an alias for the element being iterated on, and `index` is the index of the item in the rendered list. 

The test data provided in the example is a list of developers with some associated information for each. We'll render their name and main coding language in an unordered list. You can view the full JSON file [here](https://next.json-generator.com/api/json/get/4JCnNiTCr).

```html
// DataDisplay.vue file
<template>
  <div>
    <ul class="userWrap">
      <li
        v-for="(entry, index) in users"
        :item="entry"
        :key="index"
        class="user"
      >
        <h2>{{ entry.name }}</h2>
        <span>
            Primary Language: <strong>{{ entry.mainLanguage }}</strong>
        </span>
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    name: "DataDisplay"
    data: function() {
      return {
        users: []
      }
    },
    created() {
      var apiURL = "https://next.json-generator.com/api/json/get/4JCnNiTCr";
      fetch(apiURL)
        .then(res => res.json())
        .then(res => (this.users = res))
        .catch(error => console.log(error));
    }
  }
</script>
```
You should see a list of developers and their main coding language. We can now build out our buttons to filter this list.

We will be adding a list of buttons, a series of data properties, and the `v-if` directive to our results list.

Starting with the data properties. The `fkey` property is the data field that we will be keying our filtering on. `filterList` is an array of filter values we'll be checking our data against. The list of filter buttons will be built off `filterList` as well. `filter` contains the value of the current set filter. By default, we want `All` of the users to show.  

```javascript
data: function() {
  return {
    fkey: "mainLanguage",
    filterList: ["JavaScript", "Python", "PHP", "Java", "All"],
    filter: "All",
    users: []
  }
}
```

**Let's build out our filter control buttons.**

We will use the `v-for` directive again. This time, to iterate through the `filterList` array and generate our filtering values. You'll notice two new pieces in our rendered list properties, `@click` & `:class` directives. The `@click` will set the value for `filter` when the button is clicked. `:class` will set the button's class as `active` when `entry === filter`.

```html
<button
  v-for="(entry, index) in filterList"
  :item="entry"
  :key="index"
  @click="filter = entry;"
  :class="{ active: entry == filter }"
>
  {{ entry }}
</button>
```

**Next, we will connect our filtering buttons to our rendered `user ` list.**

To do this, we will add Vue's `v-if` directive to our list's properties. Our example uses `v-if="entry[fkey] === filter || filter === 'All'"`. If our entry's `mainLaguage` is equal to `filter` or if `filter` is set to `'All'`, it will return `true` and show the entry.
```html
<ul class="userWrap">
  <li
    v-for="(entry, index) in users"
    v-if="entry[fkey] === filter || filter === 'All'"
    :item="entry"
    :key="index"
    class="user"
  >
    <h2 class="title">{{ entry.name }}</h2>
    <span class="language">
      Primary Language: <strong>{{ entry.mainLanguage }}</strong>
    </span>
  </li>
</ul>
```

This is the full `DataDisplay.vue` file. I added in some CSS for fun.

```html
// DataDisplay.vue
<template>
  <div>
    <div>
      <button
        v-for="(entry, index) in filterList"
        :item="entry"
        :key="index"
        @click="filter = entry; active = index;"
        :class="{ active: entry == filter }"
      >
        {{ entry }}
      </button>
    </div>
    <ul class="userWrap">
      <li
        v-for="(entry, index) in users"
        v-if="entry[fkey] === filter || filter === 'All'"
        :item="entry"
        :key="index"
        class="user"
      >
        <h2 class="title">{{ entry.name }}</h2>
        <span class="language">
          Primary Language: <strong>{{ entry.mainLanguage }}</strong>
        </span>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "DataDisplay",
  data: function() {
    return {
      fkey: "mainLanguage",
      filterList: ["JavaScript", "Python", "PHP", "Java", "All"],
      filter: "All",
      users: []
    };
  },
  created() {
    var apiURL = "https://next.json-generator.com/api/json/get/4JCnNiTCr";
    fetch(apiURL)
      .then(res => res.json())
      .then(res => (this.users = res))
      .catch(error => console.log(error));
  }
};
</script>

<style scoped>
button {
  background: #74b6cc;
  border: none;
  color: #fff;
  padding: 10px;
  margin: 5px;
}
button.active {
  background: #0089ba;
}
.userWrap {
  list-style-type: none;
  padding: 2%;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  flex-direction: row;
}
.user {
  padding: 10px;
  margin: 1% 0;
  border: 1px solid #ddd;
  border-radius: 3px;
  width: 45%;
  text-align: left;
}
h2.title {
  font-size: 1.3rem;
  font-weight: bold;
  margin: 0;
}
.language {
  display: block;
  font-size: 0.9rem;
}
</style>

```
**The last step is to import our `DataDisplay` component into our `App.vue` file.**

```html
// App.vue
<template>
  <div id="app">
    <DataDisplay />
  </div>
</template>

<script>
import DataDisplay from "./components/DataDisplay";

export default {
  name: "App",
  components: {
    DataDisplay
  }
};
</script>

```
🍻

{% codesandbox kkvr7z5rr3 %}