How to use filter and search bar on the same form in VueJS 2

Viewed 158

Here is my code:

<div class="job-filter">
  <h3>Filter <img id="icon-filter" @click="showfilter" :style="{ 'display': display.btn_show_filter }" src="../assets/recruit/angle-down-svgrepo-com.svg" alt=""> <img id="icon-close-filter" :style="{ 'display': display.btn_close_filter }" @click="closefilter" src="../assets/recruit/close-svgrepo-com.svg" alt=""></h3>
  <div  class="radio-group" id="group-filter" :style="{ 'display': display.group_filter }" >
    <div class="radio-check" v-for="(check, index) in checks" :key="index">
      <input type="radio" :id="index"  name="fav_language" :value="check" v-model="selected" >
      <label  :for="index">{{check}}</label><br>
    </div>
  </div>
  </div>
  <div class="search">
    <div class="search-top flex-wrap">
      <div class="search-input">
        <input type="search" v-model="search" placeholder="Nhập từ khóa để tìm kiếm">
        <button @click="search"><img src="../assets/recruit/search.svg" alt=""></button>
      </div>
    </div>
    <div class="job-item"  v-for="(item, index) in filtered" :key="index">
   <a href=""><h3 class="mleft-27">{{item.position}}</h3></a>     
    <div>
      <img src="../assets/recruit/years.svg" alt="">
      <b>{{item.exprerience}}</b>
    </div>
    <div>
      <img src="../assets/recruit/luong.svg" alt="">
      <b>{{item.salary}}</b>
    </div>
    <div>
      <img src="../assets/recruit/diadiem.svg" alt="">
      <b>{{item.headequarters}}</b>
    </div>
    <h6>{{item.createdAt}}</h6>
</div>
<ul>
  <li>{{item.content1}}</li>
  <li>{{item.content2}}</li>
  <li>{{item.content3}}</li>
</ul>

I've done with the filter, but I'm having trouble building the search bar....... i'm using the filtered checkbox to handle the filter but i still haven't figured out how to make both work and show the same place.

My logic code:

export default {
  data(){
     return{     
       checks:['All','Developer','Tester', 'Designer', 'Support',],
       infojobs:[{
                  genres: 'Developer',
                  position:'Senior Java Engineer, Big Data',
                  exprerience:'3-5 Years',
                  salary:'',
                  headequarters:'',
                  content1:'1',
                  content2:'2
                  createdAt: "3"
                 },
                 {
                  genres: 'Designer',
                  position:'Creative professional designer ',
                  exprerience:'1-3 Years',
                  salary:'',
                  headequarters:'',
                  content1:'',
                  content2:'1',
                  content3:'2',
                  createdAt: "3"
                  }
        ],
        selected: 'All',
      }
    },
    computed: {
      filtered() {
        console.log(this.selected)
        if(this.selected=='All'){
            return this.infojobs
        }
        else{ 
          return this.infojobs.filter(i => i.genres === this.selected)
        }
    },                
  },

I hope to handle the search bar and filter without conflict, hope to get some help, thanks a lot...

2 Answers

You can try using the watchers.

Code explanation:

  • Define an extra variable showJobs in data()
  • Place a watcher on selected variable which will show the jobs on basis of filter selection
  • Place a watcher on search variable which triggers the search functionality only if user inputs more than 2 characters, if not, we will be showing default filtered jobs. In addition, we can use debounce to add a delay of 500ms while searching the jobs.

watch: {
 selected(newVal) {
   if (newVal === "All") {
     this.showJobs = this.infojobs;
   } else {
     this.showJobs = this.infojobs.filter((i) => i.genres === newVal);
   }
 },

 search: _.debounce(function (newVal) {
   if (newVal.length > 2) {
     let searchedJobs = this.showJobs.filter((job) =>
       job.position.toLowerCase().includes(newVal.toLowerCase())
     );

     this.showJobs = searchedJobs;
   } else {
     if (this.selected === "All") {
      this.showJobs = this.infojobs;
     } else {
      this.showJobs = this.infojobs.filter((i) => i.genres === this.selected);
    }
   }
 }, 500)
}

Note: You need import debounce from lodash library in the component.


EDIT: Here as you mentioned your requirement in the comment, you can use the same logic in the searchJob function under methods, so it triggers the 'search' functionality on button click and yea, don't forget to remove the watcher for search variable.

searchJob() {
   if (this.search.length > 2) {
     let searchedJobs = this.showJobs.filter((job) =>
       job.position.toLowerCase().includes(this.search.toLowerCase())
     );

     this.showJobs = searchedJobs;
   } else {
     if (this.selected === "All") {
      this.showJobs = this.infojobs;
     } else {
      this.showJobs = this.infojobs.filter((i) => i.genres === this.selected);
    }
   }
 },
computed: {
  filtered() {
    let finalFilter = [...this.infojobs];
    console.log(this.selected)
    if (this.selected !== 'All') {
      finalFilter =this.infojobs.filter(i => i.genres === 
    }
    if (this.search.trim()) {
      finalFilter  = finalFilter.filter((i) => Object.values(i).some(v => v.toLowerCase().includes(this.search.toLowerCase())
    }
    return finalFiter
  },                
},

You don't need if-else both. just use if condition.

Related