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