简体   繁体   中英

Filter search with computed in vue.js 3

I have this search input:

<input
class="form-control"
type="text"
name="search"
placeholder="search..."
v-model="search"
/>

And this "output" area:

<my-comp
v-for="item in filter"
:key="item.id"
:id="item.id"
:imgsrc="item.imgsrc"
:price="item.price"
:city="item.city"
:country="item.country"
:reviewnum="item.reviewnum"
:daynum="item.daynum"
/>

i imort data from json file and this is the data

[
    {"id": 1, "city":"California", "country": "United State of America", "price": "700", "reviewnum": "890", "daynum": "5", "imgsrc": "img/place/1.png"},
    {"id": 2, "city":"london", "country": "United Kingdom", "price": "550", "reviewnum": "900", "daynum": "4", "imgsrc": "img/place/2.png"},
    {"id": 3, "city":"Korola Megna", "country": "Nepal", "price": "350", "reviewnum": "150", "daynum": "5", "imgsrc": "img/place/3.png"},
    {"id": 4, "city":"Miami Beach", "country": "United State of America", "price": "850", "reviewnum": "660", "daynum": "7", "imgsrc": "img/place/4.png"},
    {"id": 5, "city":"California", "country": "United State of America", "price": "600", "reviewnum": "380", "daynum": "6", "imgsrc": "img/place/5.png"},
    {"id": 6, "city":"Saintmartine Iceland", "country": "Kingdom of the Netherlands", "price": "450", "reviewnum": "340", "daynum": "3", "imgsrc": "img/place/6.png"}
]

The idea is that the user searches a city or country or any data and the output should show only the cards he is searching for.

This is the vue js code:

import data from "@/assets/data.json";

export default {
  name: "Home",
  data: function () {
    return {
      allData: data,
      search: "",
    };
  },
  components: { myComp, foooter, headeer },
  computed: {
    filter() {
      if (!this.search) {
        return this.allData;
      } else {
        return this.allData.filter(({ country }) =>
          (country).toLowerCase().includes(this.search.toLowerCase())
        );
      }
    },
  },
};

But my function only accepts one variable. What should I do?

Search all columns:

computed: {
  filteredData() {
    return this.allData
      .filter(
        (entry) => this.allData.length
          ? Object.keys(this.allData[0])
              .some(key => ('' + entry[key]).toLowerCase().includes(this.search))
          : true
      );
  }
}

See it working:

 new Vue({ el: '#app', data: () => ({ search: '', allData: [ {"id": 1, "city":"California", "country": "United State of America", "price": "700", "reviewnum": "890", "daynum": "5", "imgsrc": "img/place/1.png"}, {"id": 2, "city":"london", "country": "United Kingdom", "price": "550", "reviewnum": "900", "daynum": "4", "imgsrc": "img/place/2.png"}, {"id": 3, "city":"Korola Megna", "country": "Nepal", "price": "350", "reviewnum": "150", "daynum": "5", "imgsrc": "img/place/3.png"}, {"id": 4, "city":"Miami Beach", "country": "United State of America", "price": "850", "reviewnum": "660", "daynum": "7", "imgsrc": "img/place/4.png"}, {"id": 5, "city":"California", "country": "United State of America", "price": "600", "reviewnum": "380", "daynum": "6", "imgsrc": "img/place/5.png"}, {"id": 6, "city":"Saintmartine Iceland", "country": "Kingdom of the Netherlands", "price": "450", "reviewnum": "340", "daynum": "3", "imgsrc": "img/place/6.png"} ] }), computed: { filteredData() { return this.allData.filter( (entry) => this.allData.length? Object.keys(this.allData[0]).some(key => ('' + entry[key]).toLowerCase().includes(this.search)): true ); } } })
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <div id="app"> <input type="search" v-model="search"> <div v-for="entry in filteredData":key="entry.id"> <pre v-text="entry" /> </div> </div>

Search specific columns:

computed: {
  filteredData() {
    return this.allData
      .filter(
        ({ country, city }) => [country, city]
          .some(val => val.toLowerCase().includes(this.search))
      );
  }
}

See it working:

 new Vue({ el: '#app', data: () => ({ search: '', allData: [ {"id": 1, "city":"California", "country": "United State of America", "price": "700", "reviewnum": "890", "daynum": "5", "imgsrc": "img/place/1.png"}, {"id": 2, "city":"london", "country": "United Kingdom", "price": "550", "reviewnum": "900", "daynum": "4", "imgsrc": "img/place/2.png"}, {"id": 3, "city":"Korola Megna", "country": "Nepal", "price": "350", "reviewnum": "150", "daynum": "5", "imgsrc": "img/place/3.png"}, {"id": 4, "city":"Miami Beach", "country": "United State of America", "price": "850", "reviewnum": "660", "daynum": "7", "imgsrc": "img/place/4.png"}, {"id": 5, "city":"California", "country": "United State of America", "price": "600", "reviewnum": "380", "daynum": "6", "imgsrc": "img/place/5.png"}, {"id": 6, "city":"Saintmartine Iceland", "country": "Kingdom of the Netherlands", "price": "450", "reviewnum": "340", "daynum": "3", "imgsrc": "img/place/6.png"} ] }), computed: { filteredData() { return this.allData.filter( ({ country, city }) => [country, city].some(val => val.toLowerCase().includes(this.search)) ); } } })
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <div id="app"> <input type="search" v-model="search"> <div v-for="entry in filteredData":key="entry.id"> <pre v-text="entry" /> </div> </div>


First one takes all keys from first entry (if you have any data) casts all values to string (so it can run .toLowerCase() on it) and checks if this.search is included in the value held in that field, for each entry.

Second one is less generic, therefore more exact. You probably want to use it when you know exactly in what fields you want to search, to prevent false positives.


Another option is to give the user a dropdown to select the column they want to filter by.

 new Vue({ el: '#app', data: () => ({ searchTerm: '', searchColumn: 'id', allData: [ {"id": 1, "city":"California", "country": "United State of America", "price": "700", "reviewnum": "890", "daynum": "5", "imgsrc": "img/place/1.png"}, {"id": 2, "city":"london", "country": "United Kingdom", "price": "550", "reviewnum": "900", "daynum": "4", "imgsrc": "img/place/2.png"}, {"id": 3, "city":"Korola Megna", "country": "Nepal", "price": "350", "reviewnum": "150", "daynum": "5", "imgsrc": "img/place/3.png"}, {"id": 4, "city":"Miami Beach", "country": "United State of America", "price": "850", "reviewnum": "660", "daynum": "7", "imgsrc": "img/place/4.png"}, {"id": 5, "city":"California", "country": "United State of America", "price": "600", "reviewnum": "380", "daynum": "6", "imgsrc": "img/place/5.png"}, {"id": 6, "city":"Saintmartine Iceland", "country": "Kingdom of the Netherlands", "price": "450", "reviewnum": "340", "daynum": "3", "imgsrc": "img/place/6.png"} ] }), computed: { columns() { return Object.keys(this.allData[0]); }, filteredData() { return this.allData.filter( entry => ('' + entry[this.searchColumn]).toLowerCase().includes(this.searchTerm) ); } } })
 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script> <div id="app"> Search <input type="search" v-model="searchTerm"> in: <select v-model="searchColumn"> <option v-for="column in columns":value="column":key="column" v-text="column" /> </select> <div v-for="entry in filteredData":key="entry.id"> <pre v-text="entry" /> </div> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM