Snippets

Duane Blake Search filter and facet in VueJs

Created by Duane Blake
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>VueJs search filter and facet</title>
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-grey-lighter">
    <div class="container mx-auto" id="app">
        <div class="flex w-3/4 mx-auto my-6">
            <input type="search" v-model="searchQuery" name="" id="" class="rounded p-2 w-full bg-grey-light border-grey-light focus:bg-white border border-solid focus:border-indigo-light text-blue-darkest" placeholder="Enter a search here!" />
        </div><!-- .class -->
        <div class="flex w-3/4 mx-auto text-indigo-darkest">
            <div class="w-1/4 mr-4">
                <div class="bg-white p-4 border border-solid border-grey-light ">
                    <p class="text-lg border-b pb-2 mb-2 ">Filter by:</p>
                    <dl class="list-reset">
                        <dt class="font-bold text-purple-dark  pb-2 uppercase">Users</dt>
                        <dd class="mb-2">
                            <input id="user1" type="checkbox" name="facet" v-model="facet" :value="1"> 
                            <label for="user1"> User 1</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user2" type="checkbox" name="facet" v-model="facet" :value="2" /> 
                            <label for="user2"> User 2</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user3" type="checkbox" name="facet" v-model="facet" :value="3"> 
                            <label for="use3"> User 3</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user4" type="checkbox" name="facet" v-model="facet" :value="4"> 
                            <label for="user4"> User 4</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user5" type="checkbox" name="facet" v-model="facet" :value="5"  />     
                            <label for="user5">User 5</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user6" type="checkbox" name="facet" v-model="facet" :value="6"> 
                            <label for="user6"> User 6</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user7" type="checkbox" name="facet" v-model="facet" :value="7"> 
                            <label for="user7"> User 7</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user8" type="checkbox" name="facet" v-model="facet" :value="8"> 
                            <label for="use8"> User 8</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user9" type="checkbox" name="facet" v-model="facet" :value="9"> 
                            <label for="user9"> User 9</label>
                        </dd>
                        <dd class="mb-2">
                            <input id="user10" type="checkbox" name="facet" v-model="facet" :value="10"  />     
                            <label for="user10">User 10</label>
                        </dd>
                    </dl>
                </div><!-- .dsadsadsadsadsds-->
            </div>
            <div class="w-3/4">
                <p class="mb-2 text-right" v-if="searchQuery && filterPosts.length > 1 ">{{filterPosts.length}} results</p>
                <ul class="list-reset bg-white p-4 border border-solid border-grey-light ">
                    <li v-if="!searchQuery">
                        <h2 class=" text-indigo-darker pb-2 text-xl">Search</h2>
                        <p class="text-black">Please use the search above</p>
                    </li>
                    <li v-for="post in filterPosts" v-else :key="post.id" class="mb-6">
                        <h2 class=" text-indigo-darker pb-2 text-xl">{{post.title}}</h2>
                        <p class="pb-2 text-black">{{post.body}}</p>
                        <p class="text-sm text-grey-darker">Posted by: User {{post.userId}}</p>
                    </li>
                    <li v-if="filterPosts.length == 0" >
                        <h2 class=" text-indigo-darker pb-2 text-xl">Sorry</h2>
                        <p class="text-black">There seem to be no posts under your criteria</p>
                    </li>
                </ul>
            </div>
        </div>
    </div><!-- .bg-blue-lightest --> 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.js"></script>
    <script>
        let app = new Vue({
            el: '#app',
            data() {
                return{
                    endpoint:      "https://jsonplaceholder.typicode.com/posts",
                    posts: [],
                    searchQuery: null,
                    facet: [],
                }
            },
            methods: {
                fetchposts() {
                    fetch(this.endpoint)
                        .then(blob => blob.json())
                        .then(data => this.posts.push(...data));
                }
            },
            computed: {
                filterPosts(){
                    return this.posts.filter(result => {
                        const myRegex = new RegExp(this.searchQuery, 'gi');
                        let resultFacet = this.facet;
                        if (resultFacet.length == 0) {
                            return (result.title.match(myRegex) || result.body.match(myRegex))
                        }
                        return (result.title.match(myRegex) || result.body.match(myRegex)) && (resultFacet.includes(result.userId)); 
                    })
                }
            },
            mounted(){
                this.fetchposts();
            }
        });
    </script>
</body>
</html>

Comments (0)