Quick & Easy Vue.js Search Facility
Tags: vue, search, filter, javascript
Published: 2020-06-05 08:57:09

Adding a search facility to your project can be complex, but only if you need it to be. Sometimes, we just need a simple filter, and return the results.

This post is going to show you how to do this in Vue.js, but the same principle can be applied to React or almost anything else.

I am going to create a simple blog style app, with a search input to filter the posts by the post's content.

You can find the finished demo app here:

[Easy Vue.js Search on codesandbox](https://codesandbox.io/s/easy-vuejs-search-icrkf?file=/src/App.vue:751-969)

And a video version on YouTube here:
https://youtu.be/mCl5LxO5FEc

To follow along, you can either use [Codesandbox](https://codesandbox.io/), and create a new project with a Vue.js starter, or use the [Vue-CLI ](https://cli.vuejs.org/guide/installation.html)to create a new project.

![Easy Vue.js Search on codesandbox](https://dev-to-uploads.s3.amazonaws.com/i/q6x9cndjk4lix510gst3.png)

This is how the starter looks in codesandbox.

Remove HelloWorld.vue from the components folder, and clean up the App.vue to look like this:

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

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

<style>
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

In the components folder, create a new file called Post.vue, and add our basic Vue.js structure:

```javascript
// components/Post.vue
<template>
  <article>
    hi
  </article>
</template>

<script>
export default {};
</script>
    
```

Next, to include the post into our app we need to register it, which I will do in the App.vue:

```javascript
// App.vue
<template>
  <div id="app">
    // 3. output component
    <post></post>
  </div>
</template>

<script>
// 1. import component 
import Post from "./components/Post";

export default {
  name: "App",
  // 2. register component
  components: { Post }
};
</script>
```

The browser should now show our message of "hi".

We now need some sample blog posts to work with and display in the Post.vue component, for this example I will add some content into the App.vue "data" property:

```javascript
// App.vue
<script>
import Post from "./components/Post";

export default {
  name: "App",
  components: { Post },
  data() {
    return {
      // add blog posts array:
      posts: [
        {
          id: 1,
          title: "Post 1",
          body: "Vue.js is cool"
        },
        {
          id: 2,
          title: "Post 2",
          body: "Javascript is cool"
        }
      ]
    };
  }
};
</script>
```

We now have 2 sample posts and with Vue.js, we can loop through each post and display the "Post" component:

```html
// App.vue
<template>
  <div id="app">
    <div v-for="post in posts" :key="post.id">
      <post></post>
    </div>
  </div>
</template>
```

We should now see the "hi" message twice in the browser. This makes sense since we have 2 blog posts.

However, we want to pass the blog post data to the Post.vue component, and we do this via props:

```javascript
// App.vue- add props to post:
<post :post="post"></post>
```

Back over in the Post.vue, we receive these props (note prop validation is skipped for simplicity):

```javascript
// components/Post.vue

<script>
export default {
  props: ["post"]
};
</script>
```

And we can modify the template to output the blog title and body:

```html
// components/Post.vue
<template>
  <article>
    <h3>{{ post.title }}</h3>
    <p>{{post.body}}</p>
  </article>
</template>
```

And we should now see the posts display in the browser!

But what about the filter? Let' begin with an input box to type in, inside of the App.vue:

```html
//App.vue
<template>
  <div id="app">
    // add input:
    <input type="text" v-model="search">
    <div v-for="post in posts" :key="post.id">
      <post :post="post"></post>
    </div>
  </div>
</template>
```

Notice here we are using v-model, this is to create 2 way data binding with a data property called search, so we also need to add this to our data property:

```javascript
  // App.vue
  ...
  
  data() {
    return {
      search: "",
      
 ...
```

This search property will now hold the value typed into the input field by the user.

We now need to get all blog posts, filter them using this search term, and return the new blog posts.

To do this, I will use a computed property. This will be ideal to re-calculate the matching blog posts each time the input is updated:

```javascript
// App.vue- final script section:

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

export default {
  name: "App",
  components: {
    Post
  },
  data() {
    return {
      search: "",
      posts: [
        {
          id: 1,
          title: "Post 1",
          body: "Vue.js is cool"
        },
        {
          id: 2,
          title: "Post 2",
          body: "Javascript is cool"
        }
      ]
    };
  },
  // Add computed section:
  computed: {
    filteredPosts() {
      return this.posts.filter(post =>
        post.body.toLowerCase().includes(this.search.toLowerCase())
      );
    }
  }
};
</script>
```

Here we are filtering the blog posts, and returning only the values which includes the search term.

This search is matching any letter, word, phrase in the blog post body section. To make the search as inclusive as possible, we also make it case insensitive by lower casing all text.

The final thing to do is to loop through this "filteredPosts" computed value, rather than all posts:

```html
// App.js
...

<div v-for="post in filteredPosts" :key="post.id">
  <post :post="post"></post>
</div>


...
```

And thats it! Go ahead and give this a test in the browser.

And now you can type into the input field, and only return blog posts which match...