Reputation: 152
Currently in my application the user can search game titles by typing in the game name. As they start typing the results update using the filter method. I'm now trying to do the same using multiple checkboxes. So when the user checks playstation and or xbox for example the results show games only from these categories. As they uncheck, the results will refresh with the updated values.
At the moment I've successfully created change events for all checkboxes and pushing their values to the filters.categories array. The problem I'm having is I have no idea how to connect this array to my existing filter method. I need to somehow loop though the array and compare the current value with category.name in my stores object to see whether they match. Is this possible to do inside the filter method? Any ideas where I'm going wrong?
Thanks in advance.
The html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<aside>
<ul>
<li>
<label>
<input type="checkbox" value="playstation" class="category-cb">
<span>Playstation</span>
</label>
<li>
<label>
<input type="checkbox" value="xbox" class="category-cb">
<span>Xbox</span>
</label>
</li>
<li>
<label>
<input type="checkbox" value="nintendo" class="category-cb">
<span>Nintendo</span>
</label>
</li>
</li>
</ul>
</aside>
<main>
<input type="text" class="store-search" placeholder="Search">
<ul class="grid"></ul>
</main>
<script src="app.js"></script>
</body>
</html>
The js:
/*----------------------------
data
----------------------------*/
const stores = [{
id: 0,
name: 'The Last Of Us',
studio: 'Naughtydog',
thumbnail: '',
category: {
id: 0,
name: 'Playstation'
},
price: 50.00
}, {
id: 1,
name: 'Animal Crossing',
studio: 'Nintendo',
thumbnail: '',
category: {
id: 1,
name: 'Nintendo'
},
price: 60.00
}, {
id: 2,
name: 'Gears 5',
studio: 'The Coalition',
thumbnail: '',
category: {
id: 2,
name: 'Xbox'
},
price: 10.00
}, {
id: 3,
name: 'DOOM Eternal',
studio: 'id Software',
thumbnail: '',
category: {
id: 3,
name: 'Playstation'
},
price: 50.00
}, {
id: 4,
name: 'The Legend of Zelda: Link\'s Awakening',
studio: 'Grezzo',
thumbnail: '',
category: {
id: 4,
name: 'Nintendo'
},
price: 35.00
}, {
id: 5,
name: 'Resident Evil 3',
studio: 'Capcom',
thumbnail: '',
category: {
id: 5,
name: 'Playstation'
},
price: 40.00
}];
let filters = {
searchText: '',
categories: []
}
/*----------------------------
functions
----------------------------*/
let filterStores = function (stores, filters) {
let filteredStores = stores.filter(function (store) {
let storeName = store.name.toLowerCase().includes(filters.searchText.toLowerCase());
return storeName;
});
let grid = document.querySelector('.grid');
grid.innerHTML = '';
filteredStores.forEach(function (store) {
let li = document.createElement('li');
li.textContent = store.name;
grid.appendChild(li);
});
}
/*----------------------------
events
----------------------------*/
document.addEventListener('DOMContentLoaded', function () {
filterStores(stores, filters);
document.querySelector('.store-search').addEventListener('input', function (event) {
filters.searchText = event.target.value;
filterStores(stores, filters);
});
document.querySelectorAll('.category-cb').forEach(function (checkbox) {
checkbox.addEventListener('change', function (event) {
if (checkbox.checked) {
filters.categories.push(event.target.value);
filterStores(stores, filters);
console.log(filters.categories);
}
});
});
});
https://jsfiddle.net/bjgp0ux4/
Upvotes: 1
Views: 2581
Reputation: 18619
There are two main features to implement:
Remove categories when they get unchecked
I recommend you to use a Set as filters.categories
, so you can easily check, add and remove entries by has
, add
and delete
, respectively.
//onchange event
if (checkbox.checked) {
filters.categories.add(event.target.value);
} else {
filters.categories.delete(event.target.value);
}
filterStores(stores, filters);
Filter the stores
based on categories as well
Modify your .filter
callback to this into account as well:
store.name.toLowerCase().includes(filters.searchText.toLowerCase()) &&
filters.categories.has(store.category.name.toLowerCase())
Also, to show all when no categories are selected, do:
store.name.toLowerCase().includes(filters.searchText.toLowerCase()) &&
(
filters.categories.has(store.category.name.toLowerCase()) ||
filters.categories.size === 0
)
All together:
/*----------------------------
data
----------------------------*/
const stores = [{
id: 0,
name: 'The Last Of Us',
studio: 'Naughtydog',
thumbnail: '',
category: {
id: 0,
name: 'Playstation'
},
price: 50.00
}, {
id: 1,
name: 'Animal Crossing',
studio: 'Nintendo',
thumbnail: '',
category: {
id: 1,
name: 'Nintendo'
},
price: 60.00
}, {
id: 2,
name: 'Gears 5',
studio: 'The Coalition',
thumbnail: '',
category: {
id: 2,
name: 'Xbox'
},
price: 10.00
}, {
id: 3,
name: 'DOOM Eternal',
studio: 'id Software',
thumbnail: '',
category: {
id: 3,
name: 'Playstation'
},
price: 50.00
}, {
id: 4,
name: 'The Legend of Zelda: Link\'s Awakening',
studio: 'Grezzo',
thumbnail: '',
category: {
id: 4,
name: 'Nintendo'
},
price: 35.00
}, {
id: 5,
name: 'Resident Evil 3',
studio: 'Capcom',
thumbnail: '',
category: {
id: 5,
name: 'Playstation'
},
price: 40.00
}];
let filters = {
searchText: '',
categories: new Set
}
/*----------------------------
functions
----------------------------*/
let filterStores = function (stores, filters) {
let filteredStores = stores.filter(store => (
store.name.toLowerCase().includes(filters.searchText.toLowerCase()) &&
(
filters.categories.has(store.category.name.toLowerCase()) ||
filters.categories.size === 0 //No selected categories, show all
)
));
let grid = document.querySelector('.grid');
grid.innerHTML = '';
filteredStores.forEach(function (store) {
let li = document.createElement('li');
li.textContent = store.name;
grid.appendChild(li);
});
}
/*----------------------------
events
----------------------------*/
document.addEventListener('DOMContentLoaded', function () {
filterStores(stores, filters);
document.querySelector('.store-search').addEventListener('input', function (event) {
filters.searchText = event.target.value;
filterStores(stores, filters);
});
document.querySelectorAll('.category-cb').forEach(function (checkbox) {
checkbox.addEventListener('change', function (event) {
if (checkbox.checked) {
filters.categories.add(event.target.value);
} else {
filters.categories.delete(event.target.value);
}
filterStores(stores, filters);
});
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<aside>
<ul>
<li>
<label>
<input type="checkbox" value="playstation" class="category-cb">
<span>Playstation</span>
</label>
</li>
<li>
<label>
<input type="checkbox" value="xbox" class="category-cb">
<span>Xbox</span>
</label>
</li>
<li>
<label>
<input type="checkbox" value="nintendo" class="category-cb">
<span>Nintendo</span>
</label>
</li>
</ul>
</aside>
<main>
<input type="text" class="store-search" placeholder="Search">
<ul class="grid"></ul>
</main>
<script src="app.js"></script>
</body>
</html>
You can also use arrays:
/*----------------------------
data
----------------------------*/
const stores = [{
id: 0,
name: 'The Last Of Us',
studio: 'Naughtydog',
thumbnail: '',
category: {
id: 0,
name: 'Playstation'
},
price: 50.00
}, {
id: 1,
name: 'Animal Crossing',
studio: 'Nintendo',
thumbnail: '',
category: {
id: 1,
name: 'Nintendo'
},
price: 60.00
}, {
id: 2,
name: 'Gears 5',
studio: 'The Coalition',
thumbnail: '',
category: {
id: 2,
name: 'Xbox'
},
price: 10.00
}, {
id: 3,
name: 'DOOM Eternal',
studio: 'id Software',
thumbnail: '',
category: {
id: 3,
name: 'Playstation'
},
price: 50.00
}, {
id: 4,
name: 'The Legend of Zelda: Link\'s Awakening',
studio: 'Grezzo',
thumbnail: '',
category: {
id: 4,
name: 'Nintendo'
},
price: 35.00
}, {
id: 5,
name: 'Resident Evil 3',
studio: 'Capcom',
thumbnail: '',
category: {
id: 5,
name: 'Playstation'
},
price: 40.00
}];
let filters = {
searchText: '',
categories: []
}
/*----------------------------
functions
----------------------------*/
let filterStores = function (stores, filters) {
let filteredStores = stores.filter(store => (
store.name.toLowerCase().includes(filters.searchText.toLowerCase()) &&
(
filters.categories.includes(store.category.name.toLowerCase()) ||
filters.categories.length === 0 //No selected categories, show all
)
));
let grid = document.querySelector('.grid');
grid.innerHTML = '';
filteredStores.forEach(function (store) {
let li = document.createElement('li');
li.textContent = store.name;
grid.appendChild(li);
});
}
/*----------------------------
events
----------------------------*/
document.addEventListener('DOMContentLoaded', function () {
filterStores(stores, filters);
document.querySelector('.store-search').addEventListener('input', function (event) {
filters.searchText = event.target.value;
filterStores(stores, filters);
});
document.querySelectorAll('.category-cb').forEach(function (checkbox) {
checkbox.addEventListener('change', function (event) {
if (checkbox.checked) {
filters.categories.push(event.target.value);
} else {
filters.categories.splice(filters.categories.indexOf(event.target.value), 1);
}
filterStores(stores, filters);
});
});
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<aside>
<ul>
<li>
<label>
<input type="checkbox" value="playstation" class="category-cb">
<span>Playstation</span>
</label>
</li>
<li>
<label>
<input type="checkbox" value="xbox" class="category-cb">
<span>Xbox</span>
</label>
</li>
<li>
<label>
<input type="checkbox" value="nintendo" class="category-cb">
<span>Nintendo</span>
</label>
</li>
</ul>
</aside>
<main>
<input type="text" class="store-search" placeholder="Search">
<ul class="grid"></ul>
</main>
<script src="app.js"></script>
</body>
</html>
Upvotes: 1