1

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

3 Answers 3

4

Use Array#some()

Something like

term = term.toLowerCase()
return data
  .filter(item => {
    return searchFields.some(field => item[field].toLowerCase().includes(term))
  }).map(...
Sign up to request clarification or add additional context in comments.

Comments

1

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>);

Comments

1

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);

3 Comments

That is really overcomplicating things.
@JonasWilms Possibly? That's not really a constructive comment. Care to elaborate?
That flag ? I mean you always check all the properties, you could actually exit after the first found.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.