how to distinguish between buttons with same className - javascript

Good day! I'm very new to Front-End development, and as a part of my homework I have got to use pure HTML, CSS and JavaScript only to make next thing:
6 button (likes) with same class name. I have different background images for one that wasn't clicked and one that was. In Demo I have background-color instead, does not matter I guess.
let pageCont = document.querySelector(`.page`);
let mainCont = pageCont.querySelector(`.container`);
let tableCont = mainCont.querySelector(`.table`);
let tableElem = tableCont.querySelector(`.table__element`);
let elemCont = tableElem.querySelector(`.table__text-container`);
var likeIcon = elemCont.querySelectorAll(`.table__like-icon`);
for (var i = 0; i < likeIcon.length; i++) {
likeIcon[i].addEventListener('onclick', function likeIconIsClicked()
{
likeIcon.classList.toggle(`table__like-icon_active`);
}
);
}
The idea was to change button(table__like-icon --> table__like-icon_acitve) properties. If I use var likeIcon = elemCont.querySelector(`.table__like-icon`) instead of querySelectorAll, I will be able to change only first found button which is not correct. So I used code that I had found on StackOverflow and tried to use it. Didn't work much. Here is the Demo http://jsfiddle.net/gasparilla/9cL7ua4r/11/
Can someone help me out?

The This keyword, specifies the caller of a function, in this case the button the user clicked on. From there on, you can change the properties of the element using the This keyword.
Here's a quick reference: https://www.w3schools.com/js/js_this.asp
var likeIcon = document.querySelectorAll(`.table__like-icon`);
for (var icon of likeIcon) {
icon.addEventListener('click', likeIconIsClicked);
}
function likeIconIsClicked() {
this.classList.toggle(`table__like-icon_active`);
}
.table__like-icon_active {
background-color: blue!important;
}
.table__like-icon {
background: red;
height: 50px;
width: 50px;
//your custom class including background-image: ,...
}
<button class="table__like-icon" type="button"></button>
<button class="table__like-icon" type="button"></button>
<button class="table__like-icon" type="button"></button>

Alternatively, you could use forEach that could remember the icon reference in every loop.
var likeIcons = document.querySelectorAll(`.table__like-icon`);
likeIcons.forEach(icon => { // change from `for` to `forEach`
icon.addEventListener('click', function() { // change from 'onclick' to 'click'
icon.classList.toggle(`table__like-icon_active`);
});
})
.table__like-icon{
width: 21px;
height: 18px;
margin: auto 22px auto auto;
background-repeat: no-repeat;
background-size: contain;
box-sizing: border-box;
background-color: red;
border: 0 none;
outline: 0;
padding: 0;
}
.table__like-icon:hover{
opacity: 0.5;
cursor: pointer;
}
.table__like-icon_active{
opacity: 1;
background-color: black;
}
<section class="table">
<div class="table__element">
<img
src="./images/kirill-pershin-1088404-unsplash.png"
alt=""
class="table__image"
/>
<div class="table__text-container">
<h2 class="table__title">FirstButton</h2>
<button class="table__like-icon" type="button"></button>
</div>
</div>
<div class="table__element">
<img
src="./images/kirill-pershin-1404681-unsplash.png"
alt=""
class="table__image"
/>
<div class="table__text-container">
<h2 class="table__title">SecondButton</h2>
<button class="table__like-icon" type="button"></button>
</div>
</div>
<div class="table__element">
<img
src="./images/kirill-pershin-1556355-unsplash.png"
alt=""
class="table__image"
/>
<div class="table__text-container">
<h2 class="table__title">ThirdButton</h2>
<button class="table__like-icon" type="button"></button>
</div>
</div>
<div class="table__element">
<img
src="./images/kirill-pershin-1404681-unsplash.png"
alt=""
class="table__image"
/>
<div class="table__text-container">
<h2 class="table__title">forthButton</h2>
<button class="table__like-icon" type="button"></button>
</div>
</div>
<div class="table__element">
<img
src="images/kirill-pershin-1556355-unsplash.png"
alt=""
class="table__image"
/>
<div class="table__text-container">
<h2 class="table__title">fifthButton</h2>
<button class="table__like-icon" type="button"></button>
</div>
</div>
<div class="table__element">
<img
src="./images/kirill-pershin-1088404-unsplash.png"
alt=""
class="table__image"
/>
<div class="table__text-container">
<h2 class="table__title">sixthtButton</h2>
<button class="table__like-icon" type="button"></button>
</div>
</div>
</section>

I guess you looking for a way to detect which button click and perform operations on that button
here you go
document.addEventListener('click', (event) => {
if (!event.target.matches('.table__like-icon')) return;
// do what ever you want to do
// event is your desire clickable button event.
event.target.style.backgroundColor = "black";
e.preventDefault();
})

Related

Two Column Accordion with Separate Full Width Divs

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.

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>

jQuery ready function for multiple drawings

I am trying to use jQuery ready function for multiple ids so that they show and hide individually without writing the same type again and again. When I try to use it on the same line it opens all the drawings all together. The code looks something like this-
<script type="text/javascript">
$(document).ready(function(){
$('#p1','#p2', '#p3','#p4').hide();
$('#p1-show','#p2-show','#p3-show','#p4-show').click(function(){
$('#p1','#p2','#p3','#p4').show();
});
$('#p1-hide','#p2-hide','#p3-hide','#p4-hide').click(function(){
$('#p1','#p2','#p3','#p4').hide();
});
});
</script>
Your function hides all of them. If you want to hide the drawing based on which show/hide button is clicked, you can use $(this) to find the corresponding drawing.
The exact code will depend on how your elements are structured, but the idea is to use $(this) to target the element that was clicked, and from there find the element you want to hide.
Here's an example:
$(document).ready(function(){
$('#p1, #p2, #p3, #p4').hide();
$('#p1-show, #p2-show, #p3-show, #p4-show').click(function(){
$(this).parent().find('p').show();
});
$('#p1-hide, #p2-hide, #p3-hide, #p4-hide').click(function(){
$(this).parent().find('p').hide();
});
});
div {
margin: 10px;
padding: 10px;
background-color: #eee;
border-radius: 10px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<p id="p1">First Drawing</p>
<button id="p1-show">Show</button>
<button id="p1-hide">Hide</button>
</div>
<div>
<p id="p2">Second Drawing</p>
<button id="p2-show">Show</button>
<button id="p2-hide">Hide</button>
</div>
<div>
<p id="p3">Third Drawing</p>
<button id="p3-show">Show</button>
<button id="p3-hide">Hide</button>
</div>
<div>
<p id="p4">Fourth Drawing</p>
<button id="p4-show">Show</button>
<button id="p4-hide">Hide</button>
</div>
The previous answers will work, but in case there are many such drawings then giving an #id to all those becomes badly repetitive and should be avoided. Following is a code snippet to make it more robust without much hard coded #ids.
$(function(){
$('.toggle-btn').on('click', function(){
var root = $(this).closest(".picture-container");
var img = $(root).find("img");
$(img).toggle();
});
});
body > div {
margin: 10px;
padding: 10px;
background-color: #eee;
border-radius: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="picture-container">
<button class="toggle-btn">Show/Hide</button>
<div>
<img src="http://24.media.tumblr.com/tumblr_lggvvf2mCm1qgnva2o1_500.gif">
</div>
</div>
<div class="picture-container">
<button class="toggle-btn">Show/Hide</button>
<div>
<img src="http://24.media.tumblr.com/tumblr_lggvvf2mCm1qgnva2o1_500.gif">
</div>
</div>
<div class="picture-container">
<button class="toggle-btn">Show/Hide</button>
<div>
<img src="http://24.media.tumblr.com/tumblr_lggvvf2mCm1qgnva2o1_500.gif">
</div>
</div>
You really don't need all of these selectors you have. It's overkill.
You should have your markup all the same for each 'drawing' it makes replication of this 'module' much easier for you also.
$(document).ready(function(){
//this hides all of your <p> on page load
$('p').hide();
//this adds the click event to all the buttons with 'show'
$('.show').on('click', function(){
$(this).parent().find('p').show();
});
$('.hide').on('click', function(){
$(this).parent().find('p').hide();
})
});
div {
margin: 10px;
padding: 10px;
background-color: #eee;
border-radius: 10px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<p>1st Image</p>
<button class="show">show</button>
<button class="hide">hide</button>
</div>
<div>
<p>2nd Image</p>
<button class="show">show</button>
<button class="hide">hide</button>
</div>
<div>
<p>3rd Image</p>
<button class="show">show</button>
<button class="hide">hide</button>
</div>
<div>
<p>4th Image</p>
<button class="show">show</button>
<button class="hide">hide</button>
</div>
<div>
<p>5th Image</p>
<button class="show">show</button>
<button class="hide">hide</button>
</div>

Javascript - set div display on click - ClassName not defined

I am trying to use the following function to change whether a div is shown or not, by clicking an image.
function showTxt(elementClass, nr) {
"use strict";
if (document.getElementByClassName(elementClass)[nr].style.display === "none") {
document.getElementByClassName(elementClass)[nr].style.display = "block";
} else {
document.getElementByClassName(elementClass)[nr].style.display = "none";
}
}
.employees{
width: 80%;
margin-left: 10%;
}
.employee{
width: 20%;
display: inline-block;
margin-left: 5%;
vertical-align: top;
margin-right: 5%;
}
.employee_img img{
width: 100%;
}
.employee_txt{
display: none;
}
<div class="employees">
<div class="employee">
<div class="employee_img">
<img src="resources/katerina.jpg" alt="katerina">
</div>
<div class="employee_txt" id="katerina"></div>
</div>
<div class="employee">
<div class="employee_img">
<img src="resources/sindre.jpg" alt="sindre">
</div>
<div class="employee_txt" id="sindre"></div>
</div>
<div class="employee">
<div class="employee_img" onclick="showTxt(employee_txt, 2)">
<img src="resources/daniel.jpg" alt="daniel">
</div>
<div class="employee_txt" id="daniel">
<p>this is me</p>
</div>
</div>
</div>
Stack's snippet tool shows the message: "Uncaught ReferenceError: employee_txt is not defined". And I have noe idea why.
Any help is appreciated.
A couple of things are wrong, it's getElementsByClassName, Elements being plural, and you need quotes around the string you're passing in your function call.
function showTxt(elementClass, nr) {
"use strict";
if (document.getElementsByClassName(elementClass)[nr].style.display === "none") {
document.getElementsByClassName(elementClass)[nr].style.display = "block";
} else {
document.getElementsByClassName(elementClass)[nr].style.display = "none";
}
}
.employees{
width: 80%;
margin-left: 10%;
}
.employee{
width: 20%;
display: inline-block;
margin-left: 5%;
vertical-align: top;
margin-right: 5%;
}
.employee_img img{
width: 100%;
}
.employee_txt{
display: none;
}
<div class="employees">
<div class="employee">
<div class="employee_img">
<img src="resources/katerina.jpg" alt="katerina">
</div>
<div class="employee_txt" id="katerina"></div>
</div>
<div class="employee">
<div class="employee_img">
<img src="resources/sindre.jpg" alt="sindre">
</div>
<div class="employee_txt" id="sindre"></div>
</div>
<div class="employee">
<div class="employee_img" onclick="showTxt('employee_txt', 2)">
<img src="resources/daniel.jpg" alt="daniel">
</div>
<div class="employee_txt" id="daniel" style="display:none;">
<p>this is me</p>
</div>
</div>
</div>
Your code
onclick="showTxt(employee_txt, 2)"
It is looking for the variable employee_txt not a string.
onclick="showTxt('employee_txt', 2)"
You have to call it
<div class="employee_img" onclick="showTxt('employee_tx', 2)">
<img src="resources/daniel.jpg" alt="daniel">
</div>
You need to use the function reference of showTxt instead of calling the function and assigning its result to the onClick handler.
To do so, use this:
onClick="showTxt.bind(showTxt, 'employee_txt', 2)"
This will return a new function that already has the 2 parameters bound to it so it can just be called as func().
I would also suggest you to use a variable inside of your showTxt function to store the result of the getElementsByClassName(classname)[index] call.

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>

Categories