Show/ hide elements on page with conditional html selects - javascript

This is most likely a duplicate, but I couldn't find snippets that help me out
I have a page with multiple images and two select fields. I want to show depending on the selection of the user different images. For the individual selects this is easy, but how can I achieve a dependency between both selects the easy way?
Example:
Items on Page: "A B", "A", "B"
User selection:
First select: A
Second select: B
Result: "A B"
User selection:
First select: A
Second select: empty
Result: "A"
I think you get the point.
The few snippets I've found are made with jQuery and I would really like to avoid jQuery and only use vanilla JS.
My current approach:
let redShown;
let blueShown;
let greenShown;
let oneShown;
let twoShown;
let threeShown;
// ColorFilter
function colorFilter(select) {
if (select.value == "red") {
redShown = true;
blueShown = false;
greenShown = false;
// Show Red
for (let i = 0; i < document.querySelectorAll(".box.red").length; i++) {
document.querySelectorAll(".box.red")[i].style.display = "inherit";
}
// Hide everything else than red
for (let i = 0; i < document.querySelectorAll(".box:not(.red)").length; i++) {
document.querySelectorAll(".box:not(.red)")[i].style.display = "none";
}
} else if (select.value == "blue") {
blueShown = true;
redShown = false;
greenShown = false;
// Show Blue
for (let i = 0; i < document.querySelectorAll(".box.blue").length; i++) {
document.querySelectorAll(".box.blue")[i].style.display = "inherit";
}
// Hide everything else than blue
for (let i = 0; i < document.querySelectorAll(".box:not(.blue)").length; i++) {
document.querySelectorAll(".box:not(.blue)")[i].style.display = "none";
}
} else if (select.value == "green") {
greenShown = true;
redShown = false;
blueShown = false;
// Show Green
for (let i = 0; i < document.querySelectorAll(".box.green").length; i++) {
document.querySelectorAll(".box.green")[i].style.display = "inherit";
}
// Hide everything else than green
for (let i = 0; i < document.querySelectorAll(".box:not(.green)").length; i++) {
document.querySelectorAll(".box:not(.green)")[i].style.display = "none";
}
}
}
// Numberfilter
function numberFilter(select) {
if (select.value == "one") {
oneShown = true;
twoShown = false;
threeShown = false;
// Show 1
for (let i = 0; i < document.querySelectorAll(".box.one").length; i++) {
document.querySelectorAll(".box.one")[i].style.display = "inherit";
}
// Hide everything else than 1
for (let i = 0; i < document.querySelectorAll(".box:not(.one)").length; i++) {
document.querySelectorAll(".box:not(.one)")[i].style.display = "none";
}
} else if (select.value == "two") {
oneShown = false;
twoShown = true;
threeShown = false;
// Show 2
for (let i = 0; i < document.querySelectorAll(".box.two").length; i++) {
document.querySelectorAll(".box.two")[i].style.display = "inherit";
}
// Hide everything else than 2
for (let i = 0; i < document.querySelectorAll(".box:not(.two)").length; i++) {
document.querySelectorAll(".box:not(.two)")[i].style.display = "none";
}
} else if (select.value == "three") {
oneShown = false;
twoShown = false;
threeShown = true;
// Show 3
for (let i = 0; i < document.querySelectorAll(".box.three").length; i++) {
document.querySelectorAll(".box.three")[i].style.display = "inherit";
}
// Hide everything else than 3
for (let i = 0; i < document.querySelectorAll(".box:not(.three)").length; i++) {
document.querySelectorAll(".box:not(.three)")[i].style.display = "none";
}
}
}
.flex-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.box {
width: 100px;
height: 100px;
margin: 10px;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
}
.box.red {
background: red;
}
.box.green {
background: green;
}
.box.blue {
background: blue;
}
<select id="colorSelect" onchange="colorFilter(this)">
<option disabled selected value="">Color</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
</select>
<select id="numberSelect" onchange="numberFilter(this)">
<option disabled selected value="">Number</option>
<option value="one">1</option>
<option value="two">2</option>
<option value="three">3</option>
</select>
<div class="flex-wrapper">
<div class="box red one">1</div>
<div class="box red two">2</div>
<div class="box red three">3</div>
<div class="box blue one">1</div>
<div class="box blue two">2</div>
<div class="box blue three">3</div>
<div class="box green one">1</div>
<div class="box green two">2</div>
<div class="box green three">3</div>
</div>
Right now the selects overwrite each other, so they don't work together.
Also my code is super complex because I write out every possible combination by hand. There has to be a shorter version for this.

You can attach the same event listener to both selects and set display properties of each box depending on the changed values of the number select and color select. PS: I tweaked HTML a little bit so it is easier to access box' variables (added data-color attribute for the color value and data-number attribute for the number value). In addition, I've changed numberSelect values from "one", "two" and "three" to "1", "2" and "3". Also, the code is 100% free of jQuery :-)
See the implementation below:
let colorSelect = document.getElementById('colorSelect');
let numberSelect = document.getElementById('numberSelect');
let boxWrapper = document.getElementById('boxWrapper');
function handleChange() {
// Get new values for changed color
// and changed number which user selected
let changedColor = colorSelect.value;
let changedNumber = numberSelect.value;
// Get the list of all boxes inside our box wrapper div
let boxes = boxWrapper.querySelectorAll('.box');
// For each box check whether its display property
// should be 'block' or 'none' based on changed values
// in colorSelect and numberSelect
boxes.forEach(box => {
// Get color and number values from the current box
let color = box.getAttribute('data-color');
let number = box.getAttribute('data-number');
// Check whether current box color and number values
// comply to user changed values in selects
let isColorValid = !changedColor || changedColor === color;
let isNumberValid = !changedNumber || changedNumber === number;
// If both color and number values comply - display the box
// otherwise hide the box using display: none
if (isColorValid && isNumberValid) {
box.style.display = 'block';
} else {
box.style.display = 'none';
}
})
}
// Attach listeners to both colorSelect and numberSelect
colorSelect.addEventListener('change', () => handleChange());
numberSelect.addEventListener('change', () => handleChange());
.flex-wrapper {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.box {
width: 100px;
height: 100px;
margin: 10px;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
}
.box.red {
background: red;
}
.box.green {
background: green;
}
.box.blue {
background: blue;
}
<select id="colorSelect">
<option disabled selected value="">Color</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
</select>
<select id="numberSelect">
<option disabled selected value="">Number</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<div class="flex-wrapper" id="boxWrapper">
<div class="box red" data-color="red" data-number="1">1</div>
<div class="box red" data-color="red" data-number="2">2</div>
<div class="box red" data-color="red" data-number="3">3</div>
<div class="box blue" data-color="blue" data-number="1">1</div>
<div class="box blue" data-color="blue" data-number="2">2</div>
<div class="box blue" data-color="blue" data-number="3">3</div>
<div class="box green" data-color="green" data-number="1">1</div>
<div class="box green" data-color="green" data-number="2">2</div>
<div class="box green" data-color="green" data-number="3">3</div>
</div>

Related

How to save new background color via `colorpicker` to `localStorage`?

I know there's a lot of similar questions.. I've tried them but I really can't incorporate it to my project.
I'm trying to save to localStorage the new background-color selected using the native colorpicker.
I'm almost there but I just can't figure out how to make it work.
Please see my code so far:
function changeBgColor(color) {
if (color) window.localStorage.setItem('bgColor', color);
else if (!(color = window.localStorage.getItem('bgColor'))) return;
document.getElementById('colorpicker').addEventListener('input', function() {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = this.value;
}
})
}
window.addEventListener('DOMContentLoaded', () => changeBgColor());
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>
<input type="color" id="colorpicker" onselect="changeBgColor();">
The important feature for me are:
To change background color using input="color"
Use class selector since I have multiple divs I want to target with the same input
Save the value to localStorage
That's all really. I just need to figure out the part where the value gets saved to localStorage.
After I make this work, I will need to replicate it for a different set of divs..
Thank you in advance for any help.
If check had = assignment instead of == comparison
Here is a working refactored snippet:
let pretend_local_storage = null
function setupBackgroundColorChange() {
const elements = document.querySelectorAll(".card-bg")
document.getElementById('colorpicker').addEventListener('input', function(e) {
color = e.target.value
if (color === pretend_local_storage) return
pretend_local_storage = color
elements.forEach((element) => element.style.background = color)
})
}
window.onDOMContentLoaded = setupBackgroundColorChange();
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>
<input type="color" id="colorpicker" onselect="changeBgColor();">
Local Storage example:
localStorage.getItem('bgColor', null)
function setupBackgroundColorChange() {
const elements = document.querySelectorAll(".card-bg")
setColor(elements, localStorage.getItem('bgColor', '#000'))
document.getElementById('colorpicker').addEventListener('input', function (e) {
color = e.target.value
if (color === localStorage.getItem('bgColor')) return
localStorage.setItem('bgColor', color)
setColor(elements, color)
})
}
function setColor(elements, color) {
elements.forEach((element) => element.style.background = color)
}
window.onDOMContentLoaded = setupBackgroundColorChange();
First of all i would use onchange trigger. To be honest, you dont need any condition inside the function. you can set the color to localStorage and that is it.
/* this lines check if already set color to localStorage */
if (window.localStorage.getItem('bgColor')) {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = this.value;
}
}
function changeBgColor() {
let color = document.getElementById('colorpicker').value;
const bg_curr = localStorage.getItem('bgColor');
console.log(color, bg_curr);
localStorage.setItem('bgColor', color);
document.getElementById('colorpicker').addEventListener('input', function() {
var elements = document.getElementsByClassName("card-bg")
for (var i = 0; i < elements.length; i++) {
elements[i].style.background = color;
}
})
}
window.addEventListener('DOMContentLoaded', () => changeBgColor());
.card1 {
width: 200px;
height: 200px;
background-color: #222;
margin: 10px 0 0 0;
}
<input type="color" id="colorpicker" onchange="changeBgColor();">
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<div class="card1 card-bg">Set A</div>
<br>

How can I make a dropdown text update after it's been selected and the user scrolls down the page using vanilla JS?

I have a dropdown menu that updates the text within the dropdown as the user scrolls through the page. The problem I have is if I select an item from the dropdown and then scroll through the page the text shown in the dropdown is not updated with the current section of the page. It works when you are scrolling through the page, so long as you don't select an item from the dropdown menu.
I want the text to update when scrolling even after the dropdown has been selected.
Here is the code in question:
const register = document.getElementById("register");
const pairing = document.getElementById("pairing");
const deviceUnlock = document.getElementById("device-unlock");
let count = 0;
function smoothScroll(stopElement) {
scrollToElement(stopElement, {
duration: 750,
});
}
const setupInstructions = [
register,
pairing,
deviceUnlock,
];
function updateNamedAnchor(urlParameters) {
history.replaceState(null, "", `#${urlParameters}`);
}
function updateUrlOnScroll() {
window.onscroll = function() {
const currentDropdownElement = document.getElementById('dropdown-current')
// replace # in url with register section
let scrolly = window.scrollY + 114;
if (scrolly < register.offsetTop) {
currentDropdownElement.textContent = 'Select Section'
updateNamedAnchor('')
count = 0;
} else if (scrolly >= register.offsetTop && scrolly < pairing.offsetTop) {
currentDropdownElement.textContent = 'Register'
updateNamedAnchor('register')
count = setupInstructions.indexOf(register);
} else if (scrolly >= pairing.offsetTop && scrolly < deviceUnlock.offsetTop) {
currentDropdownElement.textContent = 'Pairing'
updateNamedAnchor('pairing')
count = setupInstructions.indexOf(pairing);
} else if (scrolly >= deviceUnlock.offsetTop) {
currentDropdownElement.textContent = 'Device Unlock'
updateNamedAnchor('device-unlock')
count = setupInstructions.indexOf(deviceUnlock);
}
};
}
I will note that it works as intended ONLY IF I select the "Select Section" item in the dropdown.
Here is the code that handles that particular dropdown item:
function onDropdownClicked() {
const currentOption = document.getElementById('dropdown-current');
currentOption.textContent = 'Select Section';
}
function dropdownClicked() {
const dropdown = document.getElementById('nav-dropdown')
dropdown.addEventListener('click', onDropdownClicked)
}
I feel like, I'm even more confused by the fact that it works when i select the option that i added an event listener to, but the other ones won't work as intended when they are selected.
UPDATE:
HTML to go with this:
<div style="position:fixed; z-index: 50; height: 100px; width: 100%; bottom: 0; left: 0; right: 0; display: flex; flex-direction: row; justify-content: space-between; background-color: gray; height: 8%;">
<div id="prev">
<p class="button-prev"><</p>
</div>
<div id='section-dropdown' style="background-color: gray; height: 40%;">
<select id="nav-dropdown" class="text-input dropdown dropdown-arrow" onchange="window.location.href=this.value">
<option id="dropdown-current" class="dropdown-item" value="#">Select Section</option>
<option id="dropdown-register" class="dropdown-item" value="#register">Register</option>
<option id="dropdown-pairing" class="dropdown-item" value="#pairing">Pairing</option>
<option id="dropdown-device-unlock" class="dropdown-item" value="#device-unlock">Device Unlock</option>
</select>
</div>
<div id="next">
<p class="button-next">></p>
</div>
</div>

HTML Replace Select item with something more formatable

I have on a website a select box to select the language of the website:
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<select class="w3-bar-item w3-select w3-right w3-button" onchange="if (this.value) window.location.href=this.value" style="-webkit-appearance: none;">
<option value="?&lang=lu"<?php if ($_SESSION['lang'] == "lu") echo "selected='selected'";?>>Lëtzebuergesch</option>
<option value="?&lang=en"<?php if ($_SESSION['lang'] == "en") echo "selected='selected'";?>>English</option>
<option value="?&lang=fr"<?php if ($_SESSION['lang'] == "fr") echo "selected='selected'";?>>Français</option>
<option value="?&lang=de"<?php if ($_SESSION['lang'] == "de") echo "selected='selected'";?>>Deutsch</option>
</select>
This works all fine but I cannot format it as i want. I would like to replace it with something like this:
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<div class="w3-dropdown-hover">
<button class="w3-button">Dropdown</button>
<div class="w3-dropdown-content w3-bar-block w3-card-4">
Lëtzebuergesch
English
Français
Deutsch
</div>
</div>
So that when you chose the language it sets the value of &lang and sets the name of the button to the language that is selected.
I hope someone can help me with this.
You can see the select box in action here on the upper right of the site:
(https://elgaucho.lu/beta/)
Thanks for your help
Andy
Scroll a bit to see how to make a custom select. All you need are last HTML and CSS codes. Other codes are just to implement the logic with JS (I know you did that with PHP).
Standard HTML select solution.
HTML:
<select id="select">
<option value="?&lang=lu">Lëtzebuergesch</option>
<option value="?&lang=en">English</option>
<option value="?&lang=fr">Français</option>
<option value="?&lang=de">Deutsch</option>
</select>
JS:
document.addEventListener('DOMContentLoaded', function() {
const select = document.getElementById('select');
select.addEventListener('change', function() {
if (this.value) {
location.href = this.value;
}
});
// loop through select options
// and if page URL contains option value, select it
for (let i = 0; i < select.options.length; i++) {
if (location.href.includes(select.options[i].value)) {
select.value = select.options[i].value;
break;
}
}
});
Custom select solution:
HTML:
<div id="my-select">
<div id="my-select-label">Lëtzebuergesch</div>
<div id="my-select-options">
<div data-value="?&lang=lu">Lëtzebuergesch</div>
<div data-value="?&lang=en">English</div>
<div data-value="?&lang=fr">Français</div>
<div data-value="?&lang=de">Deutsch</div>
</div>
</div>
CSS:
#my-select {
width: 150px;
}
#my-select:hover #my-select-options {
display: block;
}
#my-select-options {
display: none;
}
#my-select-options > div {
padding: 0.5em;
border: 1px solid black;
border-top: none;
}
#my-select-label {
margin-top: 2em;
padding: 1em;
border: 1px solid black;
}
JS:
document.addEventListener('DOMContentLoaded', function() {
const mySelectLabel = document.getElementById('my-select-label');
const mySelectOptions = document.querySelectorAll('#my-select-options > div');
for (let i = 0; i < mySelectOptions.length; i++) {
mySelectOptions[i].addEventListener('click', function() {
location.href = this.getAttribute('data-value');
});
}
for (let i = 0; i < mySelectOptions.length; i++) {
if (location.href.includes(mySelectOptions[i].getAttribute('data-value'))) {
mySelectLabel.textContent = mySelectOptions[i].textContent;
break;
}
mySelectLabel.textContent = mySelectOptions[0].textContent;
}
});
If you have any questions, ask.

filtering elements with two select elements with plain javascript

im struggling with two select elements to sort my squares and circles.
each select element work separately, but it doesn't work together.
can anyone tell me how can i make it work right?
please help!
function colorType(){
var colorBox = document.querySelector('#selectColor');
var boxValue = colorBox.options[colorBox.selectedIndex].value;
var blue = document.querySelectorAll('.card.blue');
var red = document.querySelectorAll('.card.red');
if(boxValue == 'blue'){
for (var i = 0; i < red.length; i++){
red[i].classList.add('hidden');
}
for (var i = 0; i < blue.length; i++){
blue[i].classList.remove('hidden');
}
}
if(boxValue == 'red'){
for (var i = 0; i < blue.length; i++){
blue[i].classList.add('hidden');
}
for (var i = 0; i < red.length; i++){
red[i].classList.remove('hidden');
}
}
}
function shapeType(){
var shapeBox = document.querySelector('#selectShape');
var boxValue = shapeBox.options[shapeBox.selectedIndex].value;
var round = document.querySelectorAll('.card.round');
var square = document.querySelectorAll('.card.square');
if(boxValue == 'round'){
for (var i = 0; i < square.length; i++){
square[i].classList.add('hidden');
}
for (var i = 0; i < round.length; i++){
round[i].classList.remove('hidden');
}
}
if(boxValue == 'square'){
for (var i = 0; i < round.length; i++){
round[i].classList.add('hidden');
}
for (var i = 0; i < square.length; i++){
square[i].classList.remove('hidden');
}
}
}
.card{
width:100px;
height: 100px;
float: left;
margin: 20px;
}
.blue{
background: blue;
}
.red{
background: red;
}
.round{
border-radius: 50%;
}
.hidden{
display: none;
}
<label>Choose the color
<select id="selectColor" onchange="colorType();">
<option value=""></option>
<option value="blue">Blue</option>
<option value="red">Red</option>
</select>
</label>
<label>Choose the shape
<select id="selectShape" onchange="shapeType();">
<option value=""></option>
<option value="round">Round</option>
<option value="square">Square</option>
</select>
</label>
<div class="card-holder">
<div class="card blue round"></div>
<div class="card blue square"></div>
<div class="card blue round"></div>
<div class="card red round"></div>
<div class="card red square"></div>
<div class="card blue square"></div>
<div class="card red round"></div>
<div class="card red square"></div>
</div>
You can do the following, selecting cards, turn the HTMLCollection to Array and use filter.
The display function is quite useless but I let it so I didn't have to change the HTML.
EDIT : Detailed explanation
You need to get all the cards.
To do so, it's better to use getElementdByClassName since it returns an HTMLCollection.
querySelectorAll on the other hand returns a NodeList. HTMLCollection are live collections while that's not always the case for NodeList.
An HTMLCollection in the HTML DOM is live; it is automatically updated
when the underlying document is changed.
So once you get the card in your variable, if you add or remove cards, you don't need to update your variable value, it will be done automatically.
Trigger your function when the inputs are selected
You already did it, that's just the onchange event.
Get shape and color value
Just retrieve your selects items with document.getElementById (faster thant querySelector), then the value attribute give you the value of the selected option inside your select tag.
Display all your cards and hide the right ones
Since cards is an HTMLCollection, you can't use Array methods on it, so you need to turn it into an array with Array.from.
Then you can use forEach and remove the 'hidden' class.
To add, remove or check the existence of classes, we use the ClassList property.
To filter the Array.from(cards), use the filter method, and then you can add the 'hidden' class to the desired cards.
var cards = document.getElementsByClassName('card');
var colorSelect = document.getElementById('selectColor');
var shapeSelect = document.getElementById('selectShape');
function colorType() {
display(colorSelect.value, shapeSelect.value);
}
function shapeType() {
display(colorSelect.value, shapeSelect.value);
}
function display(color, shape) {
Array.from(cards).forEach(card => card.classList.remove('hidden'));
if (color) {
Array.from(cards)
.filter(card => !card.classList.contains(color))
.forEach(card => card.classList.add('hidden'))
}
if (shape) {
Array.from(cards)
.filter(card => !card.classList.contains(shape))
.forEach(card => card.classList.add('hidden'))
}
}
.card{
width:100px;
height: 100px;
float: left;
margin: 20px;
}
.blue{
background: blue;
}
.red{
background: red;
}
.round{
border-radius: 50%;
}
.hidden{
display: none;
}
<label>Choose the color
<select id="selectColor" onchange="colorType();">
<option value=""></option>
<option value="blue">Blue</option>
<option value="red">Red</option>
</select>
</label>
<label>Choose the shape
<select id="selectShape" onchange="shapeType();">
<option value=""></option>
<option value="round">Round</option>
<option value="square">Square</option>
</select>
</label>
<div class="card-holder">
<div class="card blue round"></div>
<div class="card blue square"></div>
<div class="card blue round"></div>
<div class="card red round"></div>
<div class="card red square"></div>
<div class="card blue square"></div>
<div class="card red round"></div>
<div class="card red square"></div>
</div>
Hope it helps,
Best regards

How to filter multiple elements/items

I'm trying to filter multiple items at once. For example fruits and animals or even 3+. So far it only does it by selecting one item at a time.How can I select more than one? I have also tried https://wch.io/static/tagsort/demo-stacks/index.html but it was bugged keept showing the text but this how it should be but in javascript?
filterSelection("all")
function filterSelection(c) {
var x, i;
x = document.getElementsByClassName("filterDiv");
if (c == "all") c = "";
for (i = 0; i < x.length; i++) {
w3RemoveClass(x[i], "show");
if (x[i].className.indexOf(c) > -1) w3AddClass(x[i], "show");
}
}
function w3AddClass(element, name) {
var i, arr1, arr2;
arr1 = element.className.split(" ");
arr2 = name.split(" ");
for (i = 0; i < arr2.length; i++) {
if (arr1.indexOf(arr2[i]) == -1) {element.className += " " + arr2[i];}
}
}
function w3RemoveClass(element, name) {
var i, arr1, arr2;
arr1 = element.className.split(" ");
arr2 = name.split(" ");
for (i = 0; i < arr2.length; i++) {
while (arr1.indexOf(arr2[i]) > -1) {
arr1.splice(arr1.indexOf(arr2[i]), 1);
}
}
element.className = arr1.join(" ");
}
.filterDiv {
float: left;
background-color: #2196F3;
color: #ffffff;
width: 100px;
line-height: 100px;
text-align: center;
margin: 2px;
display: none;
}
.show {
display: block;
}
.container {
margin-top: 20px;
overflow: hidden;
}
<h2>Filter DIV Elements</h2>
<input type="radio" onclick="filterSelection('all')" name="category" checked> Show all<br>
<input type="radio" onclick="filterSelection('cars')" name="category"> Cars<br>
<input type="radio" onclick="filterSelection('animals')" name="category"> Animals<br>
<input type="radio" onclick="filterSelection('fruits')" name="category"> Fruits<br>
<input type="radio" onclick="filterSelection('colors')" name="category"> Colors<br>
<div class="container">
<div class="filterDiv cars">BMW</div>
<div class="filterDiv colors fruits">Orange</div>
<div class="filterDiv cars">Volvo</div>
<div class="filterDiv colors">Red</div>
<div class="filterDiv cars animals">Mustang</div>
<div class="filterDiv colors">Blue</div>
<div class="filterDiv animals">Cat</div>
<div class="filterDiv animals">Dog</div>
<div class="filterDiv fruits">Melon</div>
<div class="filterDiv fruits animals">Kiwi</div>
<div class="filterDiv fruits">Banana</div>
<div class="filterDiv fruits">Lemon</div>
<div class="filterDiv animals">Cow</div>
</div>
// If we save our current state somewhere, we can easily filter the divs.
var checkedCategories = ["cars", "animals", "fruits", "colors"];
// We need a function that detects the click on a checkbox and adds/removes that category.
var changeCategory = function changeCategory(event) {
// The event object will tell us exactly what was clicked.
var checkbox = event.target;
// The category we want toa dd or remove is the attribute
var category = checkbox.getAttribute("data-category");
// To check if we already have the category in the array, we just check the index.
var savedCategoryIndex = checkedCategories.indexOf(category);
// If the checkbox is checked, that category has to already exist in the array or get added.
if (checkbox.checked && savedCategoryIndex === -1) {
checkedCategories.push(category);
}
// if it is not checked and is present in the array, it needs to be removed.
else if (!checkbox.checked && savedCategoryIndex !== -1) {
checkedCategories.splice(savedCategoryIndex, 1);
}
renderCategories();
};
// We want a reusable function that will show/hide any categories we want to see.
var renderCategories = function renderCategories() {
// We need a list of all the divs. So we just select all the divs that have the data-category attribute and slice them into an array.
// Could be replaced by Array.from() if your browser supports it.
var categoryDivs = Array.prototype.slice.call(document.querySelectorAll("div[data-category]"));
// Now we need to loop over all the divs and check if they need to get hidden or not.
categoryDivs.forEach(function(div) {
// Get all the tags the div has
var tags = div.getAttribute("data-category").split(" ");
// If at least one tag of the div is inside our categories array, we know it'll need to get shown.
var divShouldBeShown = tags.some(function(tag) {
return checkedCategories.indexOf(tag) !== -1;
});
// The decide if we need to hide the div or not.
// Can be replaced by a classList.toggle() if your browser supports it.
if (divShouldBeShown && div.className.indexOf("hidden") !== -1) {
div.className = div.className.replace("hidden", "");
} else if (!divShouldBeShown && div.className.indexOf("hidden") === -1) {
div.className = div.className + " hidden";
}
});
};
// Finally we have to add an event to the checkboxes.
document.querySelector("#categoryBoxes").addEventListener('click', changeCategory);
.hidden {
display: none;
}
<!-- I've made some changed to the structure of your program to shorten the code alot -->
<h2>Filter DIV Elements</h2>
<!--
We need checkboxes instead of radio buttons if we want to be able to select multiples.
By wrapping them inside a div, we can use one event handler instead of one onclick event for each element.
This makes adding more checkboxes later easier.
-->
<div id="categoryBoxes">
<input type="checkbox" data-category="cars" name="category" checked>Cars<br>
<input type="checkbox" data-category="animals" name="category" checked>Animals<br>
<input type="checkbox" data-category="fruits" name="category" checked>Fruits<br>
<input type="checkbox" data-category="colors" name="category" checked>Colors<br>
</div>
<div class="container">
<!--
By using data-attributes instead of a classname, we make it easier to change the classname, no need to split/rejoin etc
This seperates the javascript from the css, so you can keep the css for styling only and the data-attribute for JS
-->
<div data-category="cars" class="filterDiv">BMW</div>
<div data-category="colors fruits" class="filterDiv">Orange</div>
<div data-category="cars" class="filterDiv">Volvo</div>
<div data-category="colors" class="filterDiv">Red</div>
<div data-category="cars animal" class="filterDiv">Mustang</div>
<div data-category="colors" class="filterDiv">Blue</div>
<div data-category="animals" class="filterDiv">Cat</div>
<div data-category="animals" class="filterDiv">Dog</div>
<div data-category="fruits" class="filterDiv">Melon</div>
<div data-category="fruits animals" class="filterDiv">Kiwi</div>
<div data-category="fruits" class="filterDiv">Banana</div>
<div data-category="fruits" class="filterDiv">Lemon</div>
<div data-category="animals" class="filterDiv">Cow</div>
</div>
The attribute ID is missing on your inputs.
the attribute name groups the radio and allows only one to be checked at once but it will not help on its own to treat the inputs via a submit or javascript.
You can use CSS :checked to select siblings coming next if its only about visual(nothing submit or to treat via js) but it will still require an id in order to work as expected.
example with checkbox :
#all:checked ~ .container .filterDiv{
display: block;
}
.filterDiv, :not(#all):checked ~ .container .filterDiv{
float: left;
background-color: #2196F3;
color: #ffffff;
width: 100px;
line-height: 100px;
text-align: center;
margin: 2px;
display: none;
}
#cars:checked ~ .container .cars,
#animals:checked ~ .container .animals,
#fruits:checked ~ .container .fruits,
#color:checked ~ .container .colors{
display: block;
}
.container {
margin-top: 20px;
overflow: hidden;
}
<h2>Filter DIV Elements</h2>
<input type="checkbox" id="all" checked> Show all<br>
<input type="checkbox" id="cars"> Cars<br>
<input type="checkbox" id="animals"> Animals<br>
<input type="checkbox" id="fruits" > Fruits<br>
<input type="checkbox" id="color" > Colors<br>
<div class="container">
<div class="filterDiv cars">BMW</div>
<div class="filterDiv colors fruits">Orange</div>
<div class="filterDiv cars">Volvo</div>
<div class="filterDiv colors">Red</div>
<div class="filterDiv cars animals">Mustang</div>
<div class="filterDiv colors">Blue</div>
<div class="filterDiv animals">Cat</div>
<div class="filterDiv animals">Dog</div>
<div class="filterDiv fruits">Melon</div>
<div class="filterDiv fruits animals">Kiwi</div>
<div class="filterDiv fruits">Banana</div>
<div class="filterDiv fruits">Lemon</div>
<div class="filterDiv animals">Cow</div>
</div>
Here is an old pen of mine sorting gallerie via radio input and labels inside a form , so selection can be submited and treated on server side or via javascript. You can inspire yourself from the linked codepen where form and radio are used.
var inputs = document.getElementsByTagName("input");
var cbs = []; //will contain all checkboxes
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].type == "checkbox") {
cbs.push(inputs[i]);
}
}
filterSelection();
function filterSelection() {
var checkedVal = [],showAll = false;
for (var i = 0; i < cbs.length; i++) {
if (cbs[i].checked && cbs[i].value == "all") {
var showAll = true;
break;
} else if (cbs[i].checked) {
checkedVal.push(cbs[i].value);
}
}
var x, i;
x = document.getElementsByClassName("filterDiv");
//if (c == "all") c = "";
for (i = 0; i < x.length; i++) {
w3RemoveClass(x[i], "show");
if (!showAll) {
for (var j = 0; j < checkedVal.length; j++) {
if (x[i].className.indexOf(checkedVal[j]) > -1) {
w3AddClass(x[i], "show");
}
}
}
else {
w3AddClass(x[i], "show");
}
}
}
function w3AddClass(element, name) {
var i, arr1, arr2;
arr1 = element.className.split(" ");
arr2 = name.split(" ");
for (i = 0; i < arr2.length; i++) {
if (arr1.indexOf(arr2[i]) == -1) {
element.className += " " + arr2[i];
}
}
}
function w3RemoveClass(element, name) {
var i, arr1, arr2;
arr1 = element.className.split(" ");
arr2 = name.split(" ");
for (i = 0; i < arr2.length; i++) {
while (arr1.indexOf(arr2[i]) > -1) {
arr1.splice(arr1.indexOf(arr2[i]), 1);
}
}
element.className = arr1.join(" ");
}
.filterDiv {
float: left;
background-color: #2196F3;
color: #ffffff;
width: 100px;
line-height: 100px;
text-align: center;
margin: 2px;
display: none;
}
.show {
display: block;
}
.container {
margin-top: 20px;
overflow: hidden;
}
<h2>Filter DIV Elements</h2>
<div><input type="checkbox" onclick="filterSelection()" name="category" value="all" checked> Show all</div>
<input type="checkbox" onclick="filterSelection();" name="category" value="cars"> Cars<br>
<input type="checkbox" onchange="filterSelection();" name="category" value="animals"> Animals<br>
<input type="checkbox" onchange="filterSelection();" name="category" value="fruits"> Fruits<br>
<input type="checkbox" onchange="filterSelection()" name="category" value="colors"> Colors<br>
<div class="container">
<div class="filterDiv cars show">BMW</div>
<div class="filterDiv colors fruits">Orange</div>
<div class="filterDiv cars">Volvo</div>
<div class="filterDiv colors">Red</div>
<div class="filterDiv cars animals">Mustang</div>
<div class="filterDiv colors">Blue</div>
<div class="filterDiv animals">Cat</div>
<div class="filterDiv animals">Dog</div>
<div class="filterDiv fruits">Melon</div>
<div class="filterDiv fruits animals">Kiwi</div>
<div class="filterDiv fruits">Banana</div>
<div class="filterDiv fruits">Lemon</div>
<div class="filterDiv animals">Cow</div>
</div>
You can use check boxes instead of radio buttons to do so. Have one button called Apply which will trigger the filtering logic.
Else, if you don't want to use Apply button then you can use the technique used in https://wch.io/static/tagsort/demo-stacks/index.html
Here, user is toggling classes based on the click on the span and depending on the clicked divs(having active class), you can build your filtering logic.
Hope this helps.

Categories