Two Column Accordion with Separate Full Width Divs - javascript

The intension is to have a two column accordion, without limiting the "expand" field to the left or right column. The catch is that there will be multiple on one page. This is already created, but only button 1 is working. With the way my JS is going, it will get very very repetitive - I am looking for assistance with re-writing the JS to be multiple click friendly. Fiddle: https://codepen.io/ttattini/pen/abLzaaY
EDIT: It would also be perfect if one dropdown would close as the next is opened
HTML
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="row">
<div id="column">
<button id="button">I am Button #1</button>
<button id="button">I am Button #3</button>
</div>
<div id="column">
<button id="button">I am Button #2</button>
<button id="button">I am Button #4</button>
</div>
</div>
<div id="hidden">
<p id="content"> So here I am #1</p>
</div>
<div id="hidden">
<p id="content"> So here I am #2</p>
</div>
<div id="hidden">
<p id="content"> So here I am #3</p>
</div>
<div id="hidden">
<p id="content"> So here I am #4</p>
</div>
CSS
#hidden {
background: #ccc;
margin-top: 2%;
overflow: hidden;
transition: height 200ms;
height: 0; /* <-- set this */
}
#button {
padding: 10px;
margin-top: 5px;
width:50%;
margin-left: 10%;
cursor: pointer;
}
#row {
display: flex;
}
#column {
flex: 50%;
}
JS
$(function() {
var b = $("#button");
var w = $("#hidden");
var l = $("#content");
b.click(function() {
if (w.hasClass('open')) {
w.removeClass('open');
w.height(0);
} else {
w.addClass('open');
w.height(l.outerHeight(true));
}
});
});

The biggest issue is that you're using IDs when you should be using classes. IDs must be unique to each element in a page. When you repeat an ID, JS will only target the first element using that ID. That's why only the first one is working.
The second issue is that, because of the way the script is written, it will only target a single element. What you need to do is get all the elements you want to target by something like their class name and then loop through them, applying the event listener to each one and its appropriate children.
EDIT: Here is an example from some code I wrote for a page with multiple accordions a few weeks ago in vanilla JS
//Below I establish a counting variable and find all the accordions on the page
const acc = document.getElementsByClassName( 'accordion' );
let i;
//Looping through each accordion
for ( i = 1; i <= acc.length; i++ ) {
//Identify target for the event listener. In this case, a heading for each accordion, which I've numbered e.g. "title-1"
const title = 'title-' + i;
const label = document.getElementById( title );
//Identify target content, in this case a list that has a unique ID e.g. "list-1"
const listNum = 'list-' + i;
const list = document.getElementById( listNum );
//Add event listener to heading that toggles the active classes
label.addEventListener( 'click', function() {
label.classList.toggle( 'accordion--active' );
});
}
Of course, there's more than one way to skin a cat, but this is a working example.

I have tracked the clicked event of each button and showed the corresponding hidden content with the use of data- attribute.
I have used vanilla JavaScipt instead of jQuery.
const buttons = document.querySelectorAll('.button');
const hiddens = document.querySelectorAll('.hidden');
buttons.forEach((btn) => {
btn.addEventListener('click', btnClicked)
function btnClicked(e) {
hiddens.forEach((hidden) => {
if(e.target.dataset.btn == hidden.dataset.content) {
hidden.classList.toggle('height')
} else {
hidden.classList.remove('height')
}
})
}
})
.hidden {
background: #ccc;
margin-top: 2%;
padding-left:2%;
overflow: hidden;
transition: height 200ms;
height: 0; /* <-- set this */
}
.hidden.height {
height: 50px;
}
.button {
padding: 10px;
color: white;
background-color: #2da6b5;
border: none;
margin-top: 5px;
width:90%;
margin-left: 5%;
cursor: pointer;
}
.button:hover {
filter: brightness(.9);
}
#row {
display: flex;
}
.column {
flex: 50%;
}
<div id="row">
<div class="column">
<button class="button" data-btn="one">I am Button #1</button>
<button class="button" data-btn="three">I am Button #3</button>
</div>
<div class="column">
<button class="button" data-btn="two">I am Button #2</button>
<button class="button" data-btn="four">I am Button #4</button>
</div>
</div>
<div class="hidden" data-content="one">
<p class="content"> So here I am #1</p>
</div>
<div class="hidden" data-content="two">
<p class="content"> So here I am #2</p>
</div>
<div class="hidden" data-content="three">
<p class="content"> So here I am #3</p>
</div>
<div class="hidden" data-content="four">
<p class="content"> So here I am #4</p>
</div>
Also, please do not use the same ID at multiple elements.

Related

JavaScript Show invisible divs on click

I ran into a problem that when I click on the button, it just flips the icon but only makes the invisible fields visible on the second click. Are there any idea how to do it?
(Heres a gif to show my problem: https://ibb.co/cvz7pWC )
Also heres my code :
function moreSoc() {
var moresoc = document.getElementById("moresoc");
var btnText = document.getElementById("mbtn");
if (moresoc.style.display === "none" ) {
moresoc.style.display = "block";
mbtn.innerHTML = "More ▲";
} else {
moresoc.style.display = "none";
mbtn.innerHTML = "More ▼"
}
}
.morebutton {
border: none;
background: #fff;
color: #111;
font-size: 32px;
}
#moresoc {
display: none;
}
<div class="wrapper more">
<button class="morebutton" id="mbtn" onclick="moreSoc()">More ▲</button>
</div>
<section class="social-links" id="moresoc">
<div class="wrapper">
<h2>Others</h2>
<div class="social-link facebook">
<p>Facebook</p>
</div>
<div class="social-link instagram">
<p>Instagram</p>
</div>
<div class="social-link twitter">
<p>Twitter</p>
</div>
<div class="social-link youtube">
<p>Youtube</p>
</div>
</div>
</section>
This could be to do with you not being to read element.style.display as none the first time round. This is because it has not yet been set by JavaScript, but just by css. I suggest changing your if statement to check for not "block".
function moreSoc() {
var moresoc = document.getElementById("moresoc");
var btnText = document.getElementById("mbtn");
if (moresoc.style.display != "block" ) {
moresoc.style.display = "block";
mbtn.innerHTML = "More ▲";
} else {
moresoc.style.display = "none";
mbtn.innerHTML = "More ▼"
}
}
.morebutton {
border: none;
background: #fff;
color: #111;
font-size: 32px;
}
#moresoc {
display: none;
}
<div class="wrapper more">
<button class="morebutton" id="mbtn" onclick="moreSoc()">More ▼</button>
</div>
<section class="social-links" id="moresoc">
<div class="wrapper">
<h2>Others</h2>
<div class="social-link facebook">
<p>Facebook</p>
</div>
<div class="social-link instagram">
<p>Instagram</p>
</div>
<div class="social-link twitter">
<p>Twitter</p>
</div>
<div class="social-link youtube">
<p>Youtube</p>
</div>
</div>
</section>
ElementCSSInlineStyle.style only returns (or sets) inline styles on an element. On your first click there is no inline display property to read so your condition sets it to none. On the second click your condition finds none and sets it to block.
The answer to look for !block solves this immediate problem but it stills ties your styling to your js rather than keeping it in your CSS. This means that if the default display property of your div needs to change in your layout (inline-block, flex, etc) you would need to change it in your js as well as your CSS.
For this reason I would recommend not using inline styles at all but rather rather use Element.classList to manage applied styles from your CSS – in this case just the adding/removing of a .hidden class that sets display to none without having to know what the appropriate visible display default is.
Also, since you are querying the button element in your code anyway, it would be better to apply the click listener from your js as well rather than inline.
function moreSoc() {
const moresoc = document.getElementById("moresoc");
if (moresoc.classList.contains('hidden')) {
moresoc.classList.remove('hidden');
mbtn.innerHTML = "More ▲";
} else {
moresoc.classList.add('hidden');
mbtn.innerHTML = "More ▼"
}
}
const mbtn = document.getElementById("mbtn");
mbtn.addEventListener('click', moreSoc);
.morebutton {
border: none;
background: #fff;
color: #111;
font-size: 32px;
}
#moresoc {
}
.hidden {
display: none;
}
<div class="wrapper more">
<button class="morebutton" id="mbtn">More ▲</button>
</div>
<section class="social-links hidden" id="moresoc">
<div class="wrapper">
<h2>Others</h2>
<div class="social-link facebook">
<p>Facebook</p>
</div>
<div class="social-link instagram">
<p>Instagram</p>
</div>
<div class="social-link twitter">
<p>Twitter</p>
</div>
<div class="social-link youtube">
<p>Youtube</p>
</div>
</div>
</section>

Change styles to toggled divs

Im using filtered divs and I want to change the flex-direction of each section only when that specific section is toggled, then go back to original styles when going back to "Show all"
Here is the link for the filtered divs
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_filter_elements
The W3 Schools code is not very good. It can be improved greatly but the use of data attributes, proper event listeners and event bubbling
All we need to to to get your "flex switch" happening is add/remove a class to the ".container" to indicate if filtered or not
var container = document.querySelector(".container");
//Add an event listener to the div containing the buttons
document.getElementById("myBtnContainer").addEventListener("click", function(event) {
//remove active class from previous active button
this.querySelector(".active").classList.remove("active");
//add active class to clicked item
event.target.classList.add("active");
//Add filitered to ".container" if "All" clicked, remove otherwise
container.classList.toggle("filtered", event.target.dataset.target !== "all")
//Display chosen elements
var elements = container.querySelectorAll(".filterDiv");
for (var i = 0; i < elements.length; i++) {
//Long version of below
//var categoryArray = elements[i].dataset.category.split(",");
//var hasTargetCategory = categoryArray.includes(event.target.dataset.target);
//elements[i].classList.toggle("show",hasTargetCategory);
elements[i].classList.toggle("show", elements[i].dataset.category.split(",").includes(event.target.dataset.target));
}
})
.filterDiv {
background-color: #2196F3;
color: #ffffff;
width: 100px;
line-height: 100px;
text-align: center;
margin: 2px;
flex: none;
}
.container {
margin-top: 20px;
display: flex;
flex-wrap: wrap;
}
/* 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;
}
/*Class to change flex direction*/
.filtered {
flex-direction: column;
}
/*Hide elements without the show class*/
.filtered>.filterDiv:not(.show) {
display: none;
}
<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-category="cars">BMW</div>
<div class="filterDiv" data-category="colors,fruits">Orange</div>
<div class="filterDiv" data-category="cars">Volvo</div>
<div class="filterDiv" data-category="colors">Red</div>
<div class="filterDiv" data-category="cars,animals">Mustang</div>
<div class="filterDiv" data-category="colors">Blue</div>
<div class="filterDiv" data-category="animals">Cat</div>
<div class="filterDiv" data-category="animals">Dog</div>
<div class="filterDiv" data-category="fruits">Melon</div>
<div class="filterDiv" data-category="fruits,animals">Kiwi</div>
<div class="filterDiv" data-category="fruits">Banana</div>
<div class="filterDiv" data-category="fruits">Lemon</div>
<div class="filterDiv" data-category="animals">Cow</div>
</div>
I didn't understand what you meant by "flexible steering", would it be to replace the phrase "Show all" with the active section? This can be done with jquery, but you would have to replace the element that houses the text.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button type="button" id="all">Show all</button>
<button type="button" id="cars">cars</button>
<script>
$("#cars").on("click", function(){
$("#all").text('Cars');
});
$("#all").on("click", function(){
$("#all").text('Show All');
});
</script>
Alternative without jquery
<button id="all">Show All</button>
<button id="cars" onclick="cars()">Cars</button>
<script>
function cars() {
document.getElementById("all").innerHTML = "Cars";
}
</script>
Alternative to build the tab without so much javascript and css
Bootstrap Collapse: You can use Bootstrap Colapse which already has a structure ready and you would only have to organize the HTML with the divs as per the documentation: https://getbootstrap.com/docs/4.0/components/collapse/
Javascript behavior: Like the previous one, this is a tabbed browsing API, which is identical to the code you are using, with the difference that here you would be using the Bootstrap structure and will not require many modifications, you should note the similarity between this and the previous one, in fact what changes is only the usability, the situations in which you will use one or the other, but the purpose is the same, both seek to hide elements.
https://getbootstrap.com/docs/4.0/components/navs/#javascript-behavior

Press a button and change the color of box elsewhere on page [duplicate]

This question already has answers here:
How to change div background color on button click?
(2 answers)
Closed 3 years ago.
I'm very new to coding and have learned my very limited knowledge from forums and tutorials online. I seem to be up against a problem that I cannot for the life of me figure out.
My goal is to press one of three buttons (Leadership, Program, Team) at the top of a grid (the grid lists our services) and have the appropriate grid box change colors. For example, pressing the Leadership button would turn a grid box blue, Program would turn a grid box yellow, and Team would turn a grid box green. This means that a grid box might be linked to more than one of the buttons, as our services overlap. So depending on what button is pressed, a single grid box might change to blue, yellow, or green.
I figured out how to do toggle buttons which show the body onclick. BUT that means A LOT of redundancy. (I would have to do a grid with the appropriately colored boxes for Leadership, another one for Program, and another one for Team). So, I think I'm on the wrong path there.
I've searched toggles, buttons, anchors, event listeners, targets, you name it. It seems like it all relates to the button itself, not how the button relates to an element on the page.
I am very grateful to anyone who can point me in the right direction! Thank you!
function goToAnchor(anchor) {
var loc = document.location.toString().split('#')[0];
document.location = loc + '#' + anchor;
return false;
}
var divs = ["Div1", "Div2", "Div3", "Div4"];
var visibleDivId = null;
function divVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
.square-grey {
display: table-cell;
height: 100px;
width: 600px;
text-align: center;
vertical-align: middle;
border-radius: 5%;
/*make it pretty*/
background: #F5F5F5;
color: #999999;
padding: 10px 15px 10px 15px;
font: 20px "helvetica";
font-weight: 350;
box-shadow: 2px 3px 3px #999999;
}
div.highlit {
padding: 25px;
}
<div class="row">
<div class="buttons">
<div style="text-align:center">
<div class="col-sm-4">
Enterprise
</div>
<div class="col-sm-4">
Program
</div>
<div class="col-sm-4">
Team
</div>
</div>
</div>
</div>
<div class="inner_div">
<div id="Div1">
<div class="row">
<div style="text-align:center">
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Strategic Alignment
</div>
</div>
</div>
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Adaptive Leadership
</div>
</div>
</div>
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Portfolio Management
</div>
</div>
</div>
<div class="col-sm-3">
<div class="top-buffer">
<div class="square-grey">
Cultural Shift
</div>
</div>
</div>
</div>
</div>
</div>
<div id="Div2" style="display: none;">I'm Div Two</div>
<div id="Div3" style="display: none;">I'm Div Three</div>
</div>
</div>
Edited answer, you can add IDs to the boxes and pass them to function.
const changeColor = (elements, color) => {
elements.forEach(el => {
const element = document.querySelector(el);
element.style.backgroundColor = color;
})
}
.colorbox {
width: 100px;
height: 100px;
background-color: aquamarine;
margin-bottom: 10px;
}
<div class="colorbox" id="colorbox1"></div>
<div class="colorbox" id="colorbox2"></div>
<div class="colorbox" id="colorbox3"></div>
<button onclick="changeColor(['#colorbox1', '#colorbox3'], 'tomato')">Change 1 & 3 to tomato</button>
<button onclick="changeColor(['#colorbox1', '#colorbox2'], 'aliceblue')">Change 1 & 2 to aliceblue</button>
<button onclick="changeColor(['#colorbox2', '#colorbox3'], '#ff0000')">Change 2 & 3 to reddest</button>

Changing the function of a button in a website

So below I have some code of what I'm working with. Right now, if you just launch the website, the #picture div has a background image, and if you press any of the buttons, that picture is replaced with something else.
So what I can't figure out is how the buttons would change what they do after pressing a button. Let's say you click on Button 1 and the background image is replaced. I want the buttons to recognize what background image is in that div and change functions accordingly, in my case, I want them to change what pictures they replace the current one with.
If the current background of #picture is X, you have ABC choices, if the background of #picture is Y, you have DEF choices, would be a TLDR explanation maybe.
<div id="adventure">
<div class="picture">
</div>
<div id="choice">
<button class="button1">Val 1</button>
<button class="button2">Val 2</button>
<button class="button3">Val 3</button>
</div>
</div>
$('.button1').click(function() {
$('.picture').css('background-image',
'url("image1")'
);
});
$('.button2').click(function() {
$('.picture').css('background-image',
'url("image2")'
);
});
$('.button3').click(function() {
$('.picture').css('background-image',
'url("image3")'
);
});
I've probably gone about doing this in a bad way but I'm really at a loss on how I would do this. I can only think up of one way of doing it and that is to have a bunch of if statements depending on what background is in the #picture div but I don't know how to implement that.
This demo relies on the class .active which determines which set of buttons (called .group) are visible, whilst the other .groups remain absent. The #switch button will toggle through each group.
You must name your images according to the id of the button it belongs to.
Example:
HTML of Button
<button id="image_of_sky.png">D</button>
URL to Image
http://domain.com/path/to/image_of_sky.png
jQuery img variable
var img = "http://domain.com/path/to/"+btn;
Snippet
$('.button').click(function() {
var btn = $(this).attr('id');
var img = "https://placehold.it/330x150?text=" + btn;
$('.picture').css('background-image',
'url(' + img + ')'
);
});
$('#switch').click(function() {
var act = $('.group.active');
var next = act.next();
act.removeClass('active');
next.addClass('active');
if (act.attr('id') == "choiceGHI") {
$('#choiceABC').addClass('active');
}
});
#adventure {
width: 395px;
}
.picture {
width: 330px;
height: 150px;
border: 1px outset grey;
}
.group {
width: 330px;
display: none;
padding: 0;
}
.button {
width: 32.5%;
margin: 0;
}
.active {
display: block;
}
#switch {
float: right;
margin: -20px 0 0 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="adventure">
<div class="picture"></div>
<div id="choiceABC" class="group active">
<button id="Image1" class="button">A</button>
<button id="Image2" class="button">B</button>
<button id="Image3" class="button">C</button>
</div>
<div id="choiceDEF" class="group">
<button id="Image4" class="button">D</button>
<button id="Image5" class="button">E</button>
<button id="Image6" class="button">F</button>
</div>
<div id="choiceGHI" class="group">
<button id="Image7" class="button">G</button>
<button id="Image8" class="button">H</button>
<button id="Image9" class="button">I</button>
</div>
<button id="switch">Switch</button>
</div>

Creating a filter bar with Javascript [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I am new to Javascript and only have very basic knowledge of it at this stage.
I am trying to create a filter bar that, when clicked, would set the opacity of the non-matched items to 0.2 and the matched item would remain at full opacity.
I have uploaded the html/css to show an example on jsfiddle: https://jsfiddle.net/rebeccasmith1301/zw2aozff/
<div id="filter-bar">
<button onclick="findShoes()">Shoes</button>
<button onclick="findTops()">Tops</button>
<button onclick="findSkirts()">Skirts</button>
</div>
<div class="product-item">
<p>Shoes</p>
</div>
<div class="product-item">
<p>Tops</p>
</div>
Skirts
I have been experimenting with javascript written on a previous post that I found very helpful but due to my basic knowledge I have been unable to solve how to achieve the results I am aiming for.
I basically would like the user to be able to click on the button shoes (for example) and all of the divs that contain the word shoes to remain with full opacity and all other divs to have the class un-selected which lowers the opacity to 0.2. The divs that contain the products can be a class only, not an id as well.
Would anyone be able to help? This would be using mainly vanilla javascript.
Many thanks,
Becky
Fiddle with multiple words: https://jsfiddle.net/qucwvqfr/1/
Fiddle with white space removal: https://jsfiddle.net/d15v3x0w/1/
Don't make a function for each possible variation of content, just make one function and give that a parameter. This javascript would check the textContent of the items, strip the whitespace from them, and change classes accordingly. The hasClass, addClass, and removeClass are helpers, focus on the highlightItems function.
function hasClass(ele,cls) {
return !!ele.className.match(new RegExp('(\\s|^)'+cls+'(\\s|$)'));
}
function addClass(ele,cls) {
if (!hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp('(\\s|^)'+cls+'(\\s|$)');
ele.className=ele.className.replace(reg,' ');
}
}
var highlightItems = function(itemName) {
var p = document.getElementsByClassName("product-item");
for (var i = 0; i < p.length; i++) {
itemText = p[i].textContent.replace(/^\s+|\s+$/g,''); // you don't need the .replace() part if you don't add extra white space in the HTML
if ( !(itemText == itemName) ) {
addClass(p[i], "un-selected");
} else {
removeClass(p[i], "un-selected");
}
}
}
And you would use it like this:
<div id="filter-bar">
<button onclick="highlightItems('Shoes')">Shoes</button>
<button onclick="highlightItems('Tops')">Tops</button>
<button onclick="highlightItems('Skirts')">Skirts</button>
</div>
Note:
If you want to have multiple words inside the box, don't add any unnecessary white space inside the div tags. (You probably shouldn't do it anyway.) So the HTML usage would be like this:
<div class="product-item">Shoes and socks</div>
<div class="product-item">Tops</div>
<div class="product-item">Skirts</div>
Credits for the class-changing functions go to http://jaketrent.com/post/addremove-classes-raw-javascript/
There needs to be a reliable way to select the specified items. I propose that you add a class shoes, tops and skirts to their respective elements:
<div class="product-item shoes">
Shoes
</div>
<div class="product-item tops">
Tops
</div>
<div class="product-item skirts">
Skirts
</div>
Now, to select all elements that got shoes it's really easy:
var shoes = document.getElementsByClassName('shoes');
Selecting elements that don't have a class shoes is another story. Let say we start by collecting out all product-item elements, like so:
var products = document.getElementsByClassName('product-item');
From here on, you need to iterate all the elements inside the returned nodeList and check if they got a shoes class. A helper function that can help you with that:
function not(nodeList, cls){
var reg = new RegExp('\\b' + cls + '\\b');
return Array.prototype.reduce.call(nodeList, function(acc, el){
console.log(el, el.className.search(reg))
if(el.className.match(reg) === null){
acc.push(el);
}
return acc;
}, []);
}
So now, to get products that aren't shoes:
var notShoes = not(products, 'shoes');
To change the opacity of all the elements inside a nodeList we could use another helper function:
function changeOpacity(nodeList, opacity){
Array.prototype.forEach.call(nodeList, function(el){
el.style.opacity = opacity;
});
}
And to use it:
changeOpacity(shoes, 1.0);
changeOpacity(notShoes, 0.2);
All together in this snippet:
function find(cls) {
var clsList = document.getElementsByClassName(cls);
var products = document.getElementsByClassName('product-item');
var notCls = not(products, cls);
changeOpacity(clsList, 1.0);
changeOpacity(notCls, 0.2);
}
function not(nodeList, cls){
var reg = new RegExp('\\b' + cls + '\\b');
return Array.prototype.reduce.call(nodeList, function(acc, el){
console.log(el, el.className.search(reg))
if(el.className.match(reg) === null){
acc.push(el);
}
return acc;
}, []);
}
function changeOpacity(nodeList, opacity){
Array.prototype.forEach.call(nodeList, function(el){
el.style.opacity = opacity;
});
}
/* Styling for filter bar*/
#filter-bar{
width: 100%
}
#filter-bar button{
width: 30%
float: left;
margin: 0.5%;
}
/* Styling for products*/
.product-item{
width: 24%;
float: left;
margin: 0.5%;
background-color: red;
height: 80px;
box-sizing: border-box;
padding: 10px;
}
/* Different options for products with button click*/
.un-selected{
opacity: 0.2;
}
<div id="filter-bar">
<button onclick="find('shoes')">Shoes</button>
<button onclick="find('tops')">Tops</button>
<button onclick="find('skirts')">Skirts</button>
</div>
<div class="product-item shoes">
Shoes
</div>
<div class="product-item tops">
Tops
</div>
<div class="product-item skirts">
Skirts
</div>
<div class="product-item skirts">
Skirts
</div>
<div class="product-item shoes">
Shoes
</div>
<div class="product-item tops">
Tops
</div>
<div class="product-item skirts">
Skirts
</div>
<div class="product-item skirts">
Skirts
</div>
I have a solution with jquery:
HTML
<button class="active btn" id="all">Show All</button>
<button class="btn" id="a">Tops</button>
<button class="btn" id="b">Skirts</button>
<button class="btn" id="c">Shoes</button>
<!-- An element with an id is needed for the jQuery -->
<div id="parent">
<!-- The base class is the box. Categories are then given as accessory classes. Any div can be in more than one category -->
<div class="box product-item a b">Shoes & Tops</div>
<div class="box product-item a">Tops</div>
<div class="box product-item b">Skirts</div>
<div class="box product-item c">Shoes</div>
</div>
CSS
/* Styling for filter bar*/
#filter-bar{
width: 100%
}
#filter-bar button{
width: 30%
float: left;
margin: 0.5%;
}
/* Styling for products*/
.product-item{
width: 24%;
float: left;
margin: 0.5%;
background-color: red;
height: 80px;
box-sizing: border-box;
padding: 10px;
}
/* Different options for products with button click*/
.un-selected{
opacity: 0.2;
}
jQuery
var $btns = $('.btn').click(function() {
if (this.id == 'all') {
$('#parent > div').fadeIn(450);
} else {
var $el = $('.' + this.id).fadeIn(450);
$('#parent > div').not($el).hide();
}
$btns.removeClass('active');
$(this).addClass('active');
})
jsfiddle
function filter(me) {
var items = document.getElementsByClassName("product-item");
console.log(me.textContent);
for (var i = 0; i < items.length; i++) {
var item = items[i];
item.style.display = "";
if (item.textContent.trim() !== me.textContent.trim() && me.textContent.trim() !== "All") {
item.style.display = "none";
}
}
}
/* Styling for filter bar*/
#filter-bar{
width: 100%
}
#filter-bar button{
width: 30%
float: left;
margin: 0.5%;
}
/* Styling for products*/
.product-item{
width: 24%;
float: left;
margin: 0.5%;
background-color: red;
height: 80px;
box-sizing: border-box;
padding: 10px;
}
/* Different options for products with button click*/
.un-selected{
opacity: 0.2;
}
<div id="filter-bar">
<button onclick="filter(this)">Shoes</button>
<button onclick="filter(this)">Tops</button>
<button onclick="filter(this)">Skirts</button>
<button onclick="filter(this)">All</button>
</div>
<div class="product-item">
Shoes
</div>
<div class="product-item">
Tops
</div>
<div class="product-item">
Skirts
</div>
<div class="product-item">
Skirts
</div>
<div class="product-item">
Shoes
</div>
<div class="product-item">
Tops
</div>
<div class="product-item">
Skirts
</div>
<div class="product-item">
Skirts
</div>

Categories