Home > other >  React- Filter array based on search and dropdown values
React- Filter array based on search and dropdown values

Time:01-05

I have a page that is displaying a list of article titles. On this page, I've added a search bar and a drop-down menu to be able to filter through this array. onChange of the input field for the search I am calling setSearchTerm. I also have a drop-down filter menu for All, True and False there is an object completed in this array. Upon clicking true/or false it filters and returns based on if the article is completed or not.

Individually they are both functioning as expected, but I am having issues coming up when I am getting them both to work together. I would like to be able to search within the filtered article titles. For example. If I select "True" I would like to be able to search through all "True" articles. So the array would be filtered by both the drop-down value "True" and the words typed into the search bar.

This is where I am struggling with:

  } else if (searchTerm != "" && filter != "") {
            console.log('here')

           // return what includes the search term
            val.title.toLowerCase().includes(searchTerm.toLowerCase())
            return val
          }

With the logic, I am expecting when searching and filter are both not empty, to return what matches with the search term. At the moment, there is nothing being returned when both the drop-down and search is used.

Here is the entire logic set up:

 let posts =  articles.filter((val) => {
  // if search is empty and if "all" or nothing is selected return the entire array
  if (searchTerm == "" && filter == "" || filter == "all") {
    return val

 // if the filter is not selected, return whats included with the search term 
  } else if (filter == "" && val.title.toLowerCase().includes(searchTerm.toLowerCase())) {
      return val

 // if search is empty and filter drop down value exists return what matches with the filter 
  } else if (searchTerm == "" && val.completed.toString().includes(filter)) {
    return val

 // if there neither are empty do logic here
  } else if (searchTerm != "" && filter != "") {
    console.log('here')

   // return what includes the search term
    val.title.toLowerCase().includes(searchTerm.toLowerCase())
    return val
  }
})

Here is my full code snippet:

 import { useState, useEffect } from 'react';

const Posts = ({ articles }) => {
 

  const [searchTerm, setSearchTerm] = useState("");
  const [filter, setFilter] = useState("")

      let posts =  articles.filter((val) => {
  // if search is empty and if "all" or nothing is selected return the entire array
  if (searchTerm == "" && filter == "" || filter == "all") {
    return val

 // if the filter is not selected, return whats included with the search term 
  } else if (filter == "" && val.title.toLowerCase().includes(searchTerm.toLowerCase())) {
      return val

 // if search is empty and filter drop down value exists return what matches with the filter 
  } else if (searchTerm == "" && val.completed.toString().includes(filter)) {
    return val

 // if there neither are empty do logic here
  } else if (searchTerm != "" && filter != "") {
    console.log('here')

   // return what includes the search term
    val.title.toLowerCase().includes(searchTerm.toLowerCase())
    return val
  }
})


 return (
      <> 
<select value={filter} onChange={(event) => {setFilter(event.target.value)}} className="dropmenu dropdown-menu"> 
    <option value="">All</option>
                <option value="true">True</option>
                <option value="false">False</option>

    </select>
       <input
        type="text"
        placeholder="Search..."
        onChange={(event) => {
          setSearchTerm(event.target.value);
        }}
      />
       <h1>h1</h1>
    <ul className='list-group mb-4'>
      {posts && posts.map(post => (
        <li key={post.id} className='list-group-item'>
          {post.title}
        </li>
      ))}
    </ul>
   
    </>

  );
};

export default Posts;

How can I set up this condition to where the user can search when the articles are filtered by True or False?

Articles array:

const articles = [{"title": "title one", completed: false}, 
{"title": "article two", completed: true}, 
{"title": "testing three", completed: false}, 
{"title": "title four", completed: false}, 
{"title": "title five", completed: true}] 

CodePudding user response:

Following your original format, just move the conditional into the if statement

} else if (searchTerm != "" && filter != "" && 
              val.title.toLowerCase().includes(searchTerm.toLowerCase())) {
            console.log('here')

           // return what includes the search term
            
            return val
          }

CodePudding user response:

You need to immediately return for the boolean result of the following.

return val.title.toLowerCase().includes(searchTerm.toLowerCase());

The above line isn't mutating val, it's just calculating a boolean result by comparing if the search term matches the current title.

Your current procedure is however returning val which will be implicitly interpreted as a true value. Therefore all conditions in your .filter are returning true for every item in artcles, so no actual filtering is being done. You can fix this by using the following:

function getPosts(){
  // if search is empty and if "all" or nothing is selected return the entire array
  if (searchTerm == "" && filter == "" || filter == "all") {
      return articles

  // if the filter is not selected, return whats included with the search term or
  // if there neither are empty do logic here
  } else if (filter == "" || !(searchTerm == "" || filter == "")) {
      return articles.filter((val) => val.title.toLowerCase().includes(searchTerm.toLowerCase()));

  // if search is empty and filter drop down value exists return what matches with the filter 
  } else if (searchTerm == "") {
    return articles.filter((val) => val.completed.toString().includes(filter));
  }
}

const posts = getPosts();

CodePudding user response:

All you need to do is add this line in the last case like this

else if (searchTerm !== "" && filter !== "") {
    console.log('here')
   // return what includes the search term
    if(val.title.toLowerCase().includes(searchTerm.toLowerCase()) && val.completed.toString().toLowerCase().includes(filter.toLowerCase()))
      return val
  }

what it basically does is check if completed property in val is equal to filter and searchTerm is equal to title I just combined your logic but it code be a little neater by doing this

else if (val.title.toLowerCase().includes(searchTerm.toLowerCase()) && val.completed.toString().toLowerCase().includes(filter.toLowerCase())) {
   // return what includes the search term
      return val
  }

since it won't reach this else if and only if searchTerm and filter are both != "" so I just moved the inside condition to the else if

  •  Tags:  
  • Related