How to filter multiple elements/items - javascript

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.

Related

Show/ hide elements on page with conditional html selects

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>

How do I select which div element to show initially when I am filtering divs based on their class name?

I have filtered a set of divs below based on their class name.
This works well when I am selecting a filter button, however initially they all show.
I would like just the "2017" class to show.
Here is the code:
* filter elements*/
filterSelection("all")
function filterSelection(c) {
var x, i;
x = document.getElementsByClassName("filterDiv");
if (c == "all") c = "";
// Add the "show" class (display:block) to the filtered elements, and remove the "show" class from the elements that are not selected
for (i = 0; i < x.length; i++) {
w3RemoveClass(x[i], "show");
if (x[i].className.indexOf(c) > -1) w3AddClass(x[i], "show");
}
}
// Show filtered elements
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];
}
}
}
// Hide elements that are not selected
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(" ");
}
// Add active class to the current control button (highlight it)
var btnContainer = document.getElementById("myBtnContainer");
var btns = btnContainer.getElementsByClassName("btn");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
.container {
overflow: hidden;
}
.myBtnContainer{
margin-top: 30px;
}
.filterDiv {
display: none; /* Hidden by default */
}
/* The "show" class is added to the filtered elements */
.show {
display: block;
}
/* Style the buttons */
.btn {
border: none;
outline: none;
padding: 12px 16px;
background-color: white;
display: inline;
width: 20%;
color: #1d1d1b;
}
.btn:focus,
.btn:hover{
background-color: white;
opacity: 0.4;
color: #1d1d1b;
}
<div id="myBtnContainer">
<button class="btn" onclick="filterSelection('2013')"> 2013</button><button class="btn" onclick="filterSelection('2014')"> 2014</button><button class="btn" onclick="filterSelection('2015')"> 2015</button><button class="btn" onclick="filterSelection('2016')"> 2016</button><button class="btn active" onclick="filterSelection('2017')"> 2017</button>
</div>
<div class="container">
<div class="wine-row filterDiv 2013">
<img class="wine-bottle" src="http://chateau.flywheelsites.com/wp-content/uploads/2018/08/CUV-SASHA_2014.png" />
</div>
<div class="wine-row filterDiv 2014">
<img class="wine-bottle" src="http://chateau.flywheelsites.com/wp-content/uploads/2018/08/CUV-SASHA_2014.png" />
</div>
<div class="wine-row filterDiv 2015">
<img class="wine-bottle" src="http://chateau.flywheelsites.com/wp-content/uploads/2018/08/CUV-SASHA_2014.png" />
</div>
<div class="wine-row filterDiv 2016">
<img class="wine-bottle" src="http://chateau.flywheelsites.com/wp-content/uploads/2018/08/CUV-SASHA_2014.png" />
</div>
<div class="wine-row filterDiv 2017">
<img class="wine-bottle" src="http://chateau.flywheelsites.com/wp-content/uploads/2018/08/CUV-SASHA_2014.png" />
</div>
</div>
All of the years show initial in a list, and it is not until I select a year from the navigation that the items filter, I would like them to be filtered from the start, showing only the 2017 elements.
Well from your HTML file i see that you have already named your class and you added a filterDiv 2017 which is sufficient to filter it. You can also create an ID for each div so that you can change the preferred Div by altering with the ID.

How to retrieve the data from database according to the button value

I have a page which is showing food details.
The food has two categories. Those are Maincat, subcat.
Maincat Subcat
Indian Food north indian food
Indian Food south indian food
Italian Food Rolex Watch premier
Italian Food south italian food
Rolex Watch premier Rolex Watch
So through this page, when user click maincat value (this is a button) it should show all its particular subcat values .
for example
if user click indian food, then all sub categories of indian food should be show.
i have refer this link enter link description here
my code is
<div id="up"><button class="previous round ar">⇪</button></div>
<div style="float: right; display: inline; padding-right: 100px;">
<?php while($row2 = mysqli_fetch_array($result4)){ ?>
<div class="filterDiv <?php echo $row2[mainName]; ?>"> <?php echo "$row2[name]"; ?> <img style="width: 50px; height: 50px;" src="maincat/<?php echo $row2['image']; ?>"> </div>
<?php } ?>
</div>
<div id="parent" >
<div id="myBtnContainer" style="display: inline;">
<?php while($row1 = mysqli_fetch_array($result3)){ ?>
<div class="child">
<button class="btn draw-border" onclick="filterSelection('<?php echo $row1[3]; ?>')"><?php echo "$row1[0]"; ?><img style="width: 50px; height: 50px;" src="maincat/<?php echo $row1[1]; ?>"></button>
<div class="divider"/>
</div>
<?php } ?>
</div>
</div>
<div id="down"><button class="next round ar" style="float: left;">⇩</button></div>
<div class="clearfix">
</div>
</div>
my script
<script>
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(" ");
}
// Add active class to the current button (highlight it)
var btnContainer = document.getElementById("myBtnContainer");
var btns = btnContainer.getElementsByClassName("btn");
for (var i = 0; i < btns.length; i++) {
btns[i].addEventListener("click", function(){
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
});
}
</script>
my mysql query
$sql3="SELECT a.name,a.image,b.image,b.name FROM food_main_cat a , food_sub_cat b WHERE b.mainName=a.name GROUP BY(a.name) ";
$result3=mysqli_query($cn,$sql3);
$sql4="SELECT * FROM `food_sub_cat`";
$result4=mysqli_query($cn,$sql4);
my problem is subcat are not showing.
Here's my take on it. I've tried to simplify it. I've taken the example you linked to.
Instead of working with classes I've used data attributes.
doFilter( 'all' );
// Add active class to the current button (highlight it)
var btns = document.getElementsByClassName("btn");
for ( btn of btns ) {
btn.addEventListener("click", function(){
let current = document.getElementsByClassName("active");
current[0].classList.remove("active");
this.className += " active";
let target = this.getAttribute('data-target');
doFilter( target );
});
}
function doFilter( target ) {
let filterDivs = document.getElementsByClassName('filterDiv');
for( fDiv of filterDivs ){
let currentDiv = fDiv;
if( target == 'all' ){
currentDiv.className += ' show';
} else {
let filterTargets = currentDiv.getAttribute('data-target').split(' ');
currentDiv.classList.remove('show');
for( filterTarget of filterTargets ){
if( filterTarget == target ){
currentDiv.className += ' show';
}
}
}
}
}
.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;
}
/* Style the buttons */
.btn {
border: none;
outline: none;
padding: 12px 16px;
background-color: #f1f1f1;
cursor: pointer;
}
.btn:hover {
background-color: #ddd;
}
.btn.active {
background-color: #666;
color: white;
}
<h2>Filter DIV Elements</h2>
<div id="myBtnContainer">
<button class="btn active" data-target="all"> Show all</button>
<button class="btn" data-target="cars"> Cars</button>
<button class="btn" data-target="animals"> Animals</button>
<button class="btn" data-target="fruits"> Fruits</button>
<button class="btn" data-target="colors"> Colors</button>
</div>
<div class="container">
<div class="filterDiv" data-target="cars">BMW</div>
<div class="filterDiv" data-target="colors fruits">Orange</div>
<div class="filterDiv" data-target="cars">Volvo</div>
<div class="filterDiv" data-target="colors">Red</div>
<div class="filterDiv" data-target="cars animals">Mustang</div>
<div class="filterDiv" data-target="colors">Blue</div>
<div class="filterDiv" data-target="animals">Cat</div>
<div class="filterDiv" data-target="animals">Dog</div>
<div class="filterDiv" data-target="fruits">Melon</div>
<div class="filterDiv" data-target="fruits animals">Kiwi</div>
<div class="filterDiv" data-target="fruits">Banana</div>
<div class="filterDiv" data-target="fruits">Lemon</div>
<div class="filterDiv" data-target="animals">Cow</div>
</div>

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 can I add up numbers that appear in class names?

Take the following code:
<div id="work">
<div class="large-{{columns}} large-offset-{{columns}} columns projects">
</div>
</div>
The idea is that <div class="large-{{columns}} large-offset-{{columns}} columns projects"> can be generated an indefinite amount of times inside #work, and {{columns}} generates a number between 0 and 12.
What I want to do is run some JavaScript that goes through the numbers generated by {{columns}} and every time the sum is about to surpass 12, the associated divs get wrapped inside a new div with class "row".
The resulting HTML might look like this:
<div id="work">
<div class="row">
<div class="large-8 large-offset-4 columns projects"></div>
</div>
<div class="row">
<div class="large-6 large-offset-0 columns projects></div>
<div class="large-6 large-offset-0 columns projects"></div>
</div>
<div class="row">
<div class="large-4 large-offset-0 columns projects"></div>
<div class="large-8 large-offset-0 columns projects"></div>
</div>
<div class="row">
<div class="large-12 large-offset-0 columns projects"></div>
</div>
</div>
How can I accomplish this?
You can extract the {{columns}} values from each div's class name with the following regular expression:
/large-(\d+)\s* large-offset-(\d+)/
This computes the delta that should be added to the running sum:
var matches = /large-(\d+)\s* large-offset-(\d+)/.exec(item.className),
delta = parseInt(matches[1], 10) + parseInt(matches[2], 10);
You can make new row divs with document.createElement and fill them with clones of the original divs.
Demonstration:
function makeRowDiv(buildRow) {
var row = document.createElement('div');
row.className = 'row';
for (var i = 0; i < buildRow.length; ++i) {
row.appendChild(buildRow[i]);
}
return row;
}
window.onload = function () {
var work = document.getElementById('work'),
items = work.getElementsByTagName('div'),
newWork = document.createElement('div');
var buildRow = [],
count = 0;
for (var i = 0; i < items.length; ++i) {
var item = items[i];
if (item.className.indexOf('columns') == -1) {
continue;
}
// Extract the desired value.
var matches = /large-(\d+)\s* large-offset-(\d+)/.exec(item.className),
delta = parseInt(matches[1], 10) + parseInt(matches[2], 10);
if (count + delta > 12 && buildRow.length != 0) {
newWork.appendChild(makeRowDiv(buildRow));
count = 0;
buildRow = [];
}
buildRow.push(item.cloneNode(true));
count += delta;
}
if (buildRow.length != 0) {
newWork.appendChild(makeRowDiv(buildRow));
}
// Replace work with newWork.
work.parentNode.insertBefore(newWork, work);
work.parentNode.removeChild(work);
newWork.id = 'work';
};
body {
font-family: sans-serif;
font-size: 14px;
color: #444;
}
#work .row {
padding: 1px;
margin: 8px;
background: #deedff;
border: 1px solid #c4d1e1;
}
#work .row div {
/* display: inline; */
padding: 1px 4px 2px 4px;
margin: 4px;
background: #fff3fc;
border: 1px solid #ded3dc;
}
#work .row div div {
/* display: inline; */
padding: 1px 4px 2px 4px;
margin: 4px;
background: #eee;
border: 1px solid #ddd;
}
p {
padding: 0;
margin: 0;
}
<div id="work">
<div class="large-8 large-offset-4 columns projects">
<div class="child-div"><p>8</p></div>
<div class="child-div"><p>4</p></div>
</div>
<div class="large-6 large-offset-0 columns projects">
<div class="child-div"><p>6</p></div>
</div>
<div class="large-3 large-offset-3 columns projects">
<div class="child-div"><p>3</p></div>
<div class="child-div"><p>3</p></div>
</div>
<div class="large-4 large-offset-0 columns projects">
<div class="child-div"><p>4</p></div>
</div>
<div class="large-8 large-offset-0 columns projects">
<div class="child-div"><p>8</p></div>
</div>
<div class="large-6 large-offset-6 columns projects">
<div class="child-div"><p>6</p></div>
<div class="child-div"><p>6</p></div>
</div>
</div>
If you have enough horizontal space, you can uncomment the CSS line /* display: inline; */ to see the children of each row div arranged side by side.
I would use split or replace to get your integers and sum them up as suggested here.
Example:
var str = 'large-8 large-offset-6';
var large = str.replace(/.*large-(\d+)/, '$1');
var offset = str.replace(/.*large-offset-(\d+)/, '$1');
Then use a solution such as this to get your wrappers.
Example:
var divs = $("#work > .columns");
var count = <count how many cols are need to reach sum>
for(var i = 0; i < divs.length; i+=count) {
divs.slice(i, i+count).wrapAll("<div class='new'></div>");
}
I'm sure you can clean it up and finish it off but should give you the idea. I will complete when I get time tonight.

Categories