Reputation:
I'm trying to set up a search function in my fictional movie rental website where the user can fill a form that takes inputs on the film title, actor, director, genre and country. the way the search function is set up now is that the user can only search one thing at a time. for example only find movies from a certiain genre and no more specifications is allowed. I want to set it up so that the user can fill as many of the search fields as they want to get a more specific search but I cant come up with a solution. any tips and help would be appreciated. here is one of the search functions to give you an idea, all of them are about the same:
function search_for_title(search) {
var results = [];
for (index in search_results) {
title = search_results[index].otitle;
movies_object[index].genres = genres_object[index]; //henter sjanger info fra genres_object databasen
lowTitle = title.toLowerCase();
lowSearch = search.toLowerCase();
if (lowTitle.includes(lowSearch)) {
results.push(movies_object[index]);
}
}
displayResults(results);
}
This is how the functions run, I'm sure this is the part of the code that needs to be modified:
window.onload = function() {
query_params = get_query_string_parameters();
search_results = movies_object;
if (query_params.film_title) {
search_for_title(query_params.film_title);
}
if (query_params.actor) {
search_for_actor(query_params.actor);
}
if (query_params.director) {
search_for_director(query_params.director)
}
if (query_params.genre) {
search_for_genre(query_params.genre)
}
if (query_params.country) {
search_for_country(query_params.country)
}
}
Upvotes: 0
Views: 7156
Reputation: 11
I know that this is the old one, but as far as I can see, I wasn't able to find some good solution for this issue. Thinking a bit about the problem, I figure that there is a simple solution, by adding dummy classes to the table data fields that doesn't match the search. By adding dummy class we can later check all elements that have that specific class (in my example "hide"), and we will finally add style "display: none" to the parent table row. There is also an event listener for backspace button that will remove dummy class in case search input is the same as field values.
Also, I'm coming from the world of python, so please don't mind if my JS isn't beautiful.
function myFunction(input_id, col, e) {
e = e || event;
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById(input_id);
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("input")[col];
if (td) {
txtValue = td.value;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
td.style.display = ""
} else {
td.classList.add("hide")
}
}
}
if (e.keyCode == 8) {
input = document.getElementById(input_id);
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("input")[col];
if (td) {
txtValue = td.value;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
td.classList.remove("hide")
}
}
}
}
var allRows;
allRows = document.getElementsByClassName("tbl_row")
for (i = 0; i < allRows.length; i++) {
allRows[i].style.display = ""
}
var searchHidden;
searchHidden = document.getElementsByClassName("hide")
for (i = 0; i < searchHidden.length; i++) {
searchHidden[i].parentElement.parentElement.style.display = "none"
}
}
<div class="equipment-preview">
<table id="myTable">
<thead>
<tr>
<th>Id</th>
<th>Movie</th>
<th>Genre</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" onkeyup="myFunction(id, 0)" id="movie_id" placeholder="search" class="searchField"></td>
<td><input type="text" onkeyup="myFunction(id, 1)" id="movie" placeholder="search" class="searchField"></td>
<td><input type="text" onkeyup="myFunction(id, 2)" id="genre" placeholder="search" class="searchField"></td>
</tr>
<tr class="tbl_row">
<td><input type="text" value="1"></td>
<td><input type="text" value="The Mask"></td>
<td><input type="text" value="Comedy"></td>
</tr>
<tr class="tbl_row">
<td><input type="text" value="2"></td>
<td><input type="text" value="Fast and furious"></td>
<td><input type="text" value="Action"></td>
</tr>
<tr class="tbl_row">
<td><input type="text" value="3"></td>
<td><input type="text" value="Home alone"></td>
<td><input type="text" value="Comedy"></td>
</tr>
<tr class="tbl_row">
<td><input type="text" value="4"></td>
<td><input type="text" value="The Hangover"></td>
<td><input type="text" value="Comedy"></td>
</tr>
</tbody>
</table>
</div>
Upvotes: 0
Reputation: 6282
If you have to do it front end you could do something like this.
it's boxing up your movies and filtering the movies in stages so you can filter with multiple attributes. The filters happen in the order to choose the most specific to the least specific filters in hopes of reducing the loops required to get the final list.
const movies = [
{ title: 'foo', actors: ['jack', 'jill'], genre: 'comedy' },
{ title: 'bar', actors: ['jack', 'jane'], genre: 'drama' },
{ title: 'baz', actors: ['josh', 'jane'], genre: 'drama' },
{ title: 'box', actors: ['jed', 'regena'], genre: 'drama' }
]
const filterBy = (prop, value) => movies =>
value === ''
? movies
: movies.filter(movie =>
Array.isArray(movie[prop])
? movie[prop].some(x => x === value)
: movie[prop] === value
)
const moviesToListItems = movies =>
movies.map(movie => (
`<div class="movie">
<h4>${movie.title}</h4>
<p>${movie.actors.join()}</p>
<span>${movie.genre}</span>
</div>`
)).join('')
const filterMovies = ({ title, actors, genre }) => movies =>
[movies]
.map(filterBy('title', title))
.map(filterBy('genre', genre))
.map(filterBy('actors', actors))
.map(moviesToListItems)
.pop()
const el = selector => document.querySelector(selector)
const search = el('#search')
const output = el('#output')
const searchMovies = movies => e => {
output.innerHTML = filterMovies({
title: el('#title').value,
actors: el('#actors').value,
genre: el('#genre').value
})(movies)
}
search.addEventListener('click', searchMovies(movies))
body { font-family: sans-serif } div { display: flex; border: 1px solid #eee } .movie { display: flex; flex: 1; flex-direction: column } .movie > * { flex: 1 } h4 { margin: 0 }
<form>
<input name="title" id="title" placeholder="title" />
<input name="actors" id="actors" placeholder="actor" />
<input name="genre" id="genre" placeholder="genre" />
<input type="button" id="search" value="search" />
</form>
<div id="output"></div>
Upvotes: 1