简体   繁体   中英

Dynamic array filtering by object property

I have a react live search dropdown component that filters through an array of objects by a search term. It filters my objects by title and then returns a list of all the related objects. This works fine.

Current:

Data Structure

data: [
    { id: 1, title: 'Some title here' },
    { id: 2, title: 'Another title' },
    { id: 3, title: 'last title' },
]

Component

   <LiveSearch
        term={term}
        data={data} />

Inside Live search component

Filter data by term and render list

return data
        .filter(item => item.title.toLowerCase().includes(term.toLowerCase())
        .map((item, idx) => <li key={idx}>{item.title}</li>

My objects to search by are getting more advanced and what I would like to be able to do is pass into my component an array of property names I would like to compare to the search term.

My thinking process behind it is to loop through the object properties and if on of the properties matches the term the loop breaks and returns true adding that object to the list of items to be displayed.

Goal

Data Structure

data: [
    { id: 1, country: 'Canada', title: 'Some title here' },
    { id: 2, country: 'Australia', title: 'Another title' },
    { id: 3, country: 'Netherlands', title: 'last title' },
]

Component

<LiveSearch
   searchFields={['country', 'title']}
   term={term}
   data={data} />

Inside Component filtering

return data
         .filter(item => {
            // Dynamic filtering of terms here
         })
         .map((item, idx) => <li key={idx}>{item.title}</li>

Inside the filter I'm trying to get a loop through the array and dynamically produce logic similar to this

item.searchFields[0].toLowerCase().includes(term.toLowerCase()) ||
item.searchFields[1].toLowerCase().includes(term.toLowerCase())

But obviously could loop over an infinite number of searchfields/properties

Use Array#some()

Something like

term = term.toLowerCase()
return data
  .filter(item => {
    return searchFields.some(field => item[field].toLowerCase().includes(term))
  }).map(...

Check if some of the searchFields match:

// Checks wether a value matches a term
const matches = (value, term) => value.toLowerCase().includes(term.toLowerCase());

 // Checks wether one of the fields in the item matcues the term
 const itemMatches = (fields, term) => item => fields.some(field => matches(item[field], term);

 // Filter the data to only contain items where on of the searchFields matches the term
 const result = props.data.filter( itemMatches(props.searchFields, props.term) );

 return result.map(item => <li key={idx}>{item.title}</li>);

You can use Array .some combined with .filter

let result = data.filter(obj => 
  searchFields.some(s => 
  obj[s] != undefined && obj[s].toLowerCase() === term
));

 let data = [ { id: 1, country: 'Canada', title: 'Some title here' }, { id: 2, country: 'Australia', title: 'Another title' }, { id: 3, country: 'Netherlands', title: 'last title' }, ], searchFields = ["country", "title"], term = "canada"; let result = data.filter(obj => searchFields.some(s => obj[s] != undefined && obj[s].toLowerCase() === term )); console.log(result); 

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