HTML and Javascript - Detecting which div box was clicked? - javascript

If I have multiple div boxes lined up (not overlapping), how can I detect which box is clicked?
For example, here is pseudocode:
HTML:
<div id="box1" onClick="clicked()">Box 1</div>
<div id="box2" onClick="clicked()">Box 2</div>
<div id="box3" onclick="clicked()">Box 3</div>
JS:
function clicked(){
var first="box1";
var second="box2";
var third="box3";
if (the div id of what you clicked is equal to first)
/*do something here*/
if (the div id of what you clicked is equal to second)
/*do something here*/
etc
etc
}
My main problem is that I don't know how to properly write the if statement. I'm not sure how to get the div's id that you clicked in JavaScript. I'm thinking of something like this:
if (document.getElementById() = first)
/*do stuff*/
I'm aware that I can solve this problem by having three different functions such as clicked1(), clicked2(), and clicked3(), but I would prefer not to have so many functions.
Any help is appreciated, thank you.

Pure Javascript has a built in target in the event object. This is basically the opposite of getElementById, its basically getIdByElement(though this method doesn't exist). To access it all you need to do is edit your HTML from onClick="clicked()" to onClick="clicked(event)" and change your clicked function into code similar to this:
function clicked(event) {
var id = event.target.id,
first = 'box1',
second = 'box2',
third = 'box3';
if(id === first) {
...
} else if(id === second) {
...
} else if(id === third) {
...
}
}
To explain why this works, when a JavaScript event is fired you get an object about it, it looks like this:
This is so that you can get certain details about what happened. In this case, you wanted the target id. This works by selecting all divs on the page. Also to shorten the code if you want, you can pass in this instead and do this.id. Such as:
function clicked(reference) { //pass in this instead of event
let id = reference.id;
...
}
Here is an example of it in work:
function clicked(event) {
let p = document.getElementById('clicked-item')
p.textContent = event.target.id + ' clicked';
}
<div id="box1" onClick="clicked(event)">Box 1</div>
<div id="box2" onClick="clicked(event)">Box 2</div>
<div id="box3" onclick="clicked(event)">Box 3</div>
<p id="clicked-item">none clicked</p>
It is a good idea to separate HTML and JS(though not 100% necessary). So to remove the onClick attribute on each element do something like this:
let selector = document.getElementsByTagName('div')
for(let element of selector) {
element.addEventListener('click', function(event) {
clicked(event);
});
}
The code starts by getting all elements that are a div with getElementsByTagName, though you can use other selectors too. Then using a for loop we loop through all the divs and add an onClick event running clicked.

You could make this work using inline event handlers but it'd be better to move your binding code to your actual scripts. You can still use one function, just apply it to each element.
The click handler will receive an event object which gives information about the click. Part of that is the .target property which will give you the source of the click event i.e, the element you clicked on.
function clicked(e) {
var target = e.target;
console.log(target.id);
}
document.querySelector('#box1').addEventListener('click', clicked);
document.querySelector('#box2').addEventListener('click', clicked);
document.querySelector('#box3').addEventListener('click', clicked);
.box {
float: left;
width: 100px;
height: 100px;
margin-right: 2px;
background-color: #000;
color: #EEE;
}
<div id="box1" class="box">Box 1</div>
<div id="box2" class="box">Box 2</div>
<div id="box3" class="box">Box 3</div>
If you're hellbent on using inline bindings, the simplest way to do this would be to pass this into your function call. That will pass the element directly.
function clicked(target) {
console.log(target.id);
}
.box {
float: left;
width: 100px;
height: 100px;
margin-right: 2px;
background-color: #000;
color: #EEE;
}
<div id="box1" class="box" onclick="clicked(this)">Box 1</div>
<div id="box2" class="box" onclick="clicked(this)">Box 2</div>
<div id="box3" class="box" onclick="clicked(this)">Box 3</div>

By adding clicked(this) it selects the div you click on and returns that specific div's data.
<div id="box1" onClick="clicked(this)">Box 1</div>
<div id="box2" onClick="clicked(this)">Box 2</div>
<div id="box3" onclick="clicked(this)">Box 3</div>
By adding the div as a parameter it specifies the div you clicked on's internal data, and adding a switch statement to trigger a specific response to each div.
function clicked(div) {
if(div.id = 'box1') {
console.log('1');
} else if(div.id = 'box2') {
console.log('2');
} else if(div.id = 'box3') {
console.log('3');
}
}

Related

Add a style to a class onclick a button

I have these 3 Boxes with the same classes and a button:
function turnRedAndAddPadding() {
/* ??? */
}
.box {
border: 1px solid;
display: inline;
}
<button onclick="turnRedAndAddPadding();">Press</button>
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box">Box 3</div>
I want to add styles to the class .box when clicking on the button without adding a new class to the boxes. Basically, if you press the button, the class .box should get a red background color and a padding and all the elements that have this class should have the same. Is there an easy way in JavaScript to solve this problem?
Thanks in advance.
You don't really want to add properties to the existing class. What you should do is add a new class that contains those red/padding properties to each element's class list.
Toolkit
You need some way to "pick up" the elements for processing. Since you have more than one querySelectorAll is probably the go-to choice which will give you a static nodelist (rather than a live HTML collection that methods like getElementsByClassName give you which have some side-effects if you don't use them correctly.)
You'll want a way to iterate over the elements to the processing. There are a number of possibilities provided in that link but forEach is a good choice here.
You'll want a way to update the class list of each element in the iteration. The unsuprisingly-named classList has, among its methods, add which accepts a string of the CSS class you want to add.
Define a new class ("redpad" in this example) that can be used.
Finally, because you want to avoid inline JS in 2023, you should be using addEventListener which accepts a) an event type and b) the name of the function you want to call when that event is fired.
const button = document.querySelector('button');
const boxes = document.querySelectorAll('.box');
button.addEventListener('click', turnRedAndAddPadding);
function turnRedAndAddPadding() {
boxes.forEach(box => {
box.classList.add('redpad');
});
}
.box {
border: 1px solid;
display: inline;
}
.redpad {
background-color: red;
padding: 0.5em;
}
<button type="button">Press</button>
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box">Box 3</div>
Based on that post you could try something like this:
function turnRedAndAddPadding() {
stylesheet = document.styleSheets[0]
stylesheet.insertRule(".box { background-color: red; padding: 10px;}", 0);
}
.box {
border: 1px solid;
display: inline;
}
<button onclick="turnRedAndAddPadding();">Press</button>
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box">Box 3</div>
Hope it helps.
Some really useful documentation by W3 Schools talks about how to use getElementsByClassName which you can find here You can find about editing the padding as well from here via the padding property of each element.
Below I am finding all div's that have the class box. Then iterating over each of them and assigning the colour and padding. You can change this to your liking.
There are also many other properties that you can edit for each DOM element like divs!
function turnRedAndAddPadding() {
const collection = document.getElementsByClassName('box');
for (let i = 0; i < collection.length; i++) {
collection[i].style.backgroundColor = 'red';
collection[i].style.padding = '5px';
}
}
Just adding some javascript you can achieve your goal.
document.querySelectorAll with this you can collect all elements with class box and then loop with a foreach function
function turnRedAndAddPadding() {
let box = document.querySelectorAll('.box');
box.forEach(el => {
el.style.background = 'red';
el.style.padding = '20px'
})
}
.box {
border: 1px solid;
display: inline;
}
<button onclick="turnRedAndAddPadding()">Press</button>
<div class="box">Box 1</div>
<div class="box">Box 2</div>
<div class="box">Box 3</div>

how can i have one function be used on multiple items without creating seperate ids?

I have a game where there are balloons and each balloon has an onclick attribute which passes the id into a JS function to change the css.
Example:
<div id="balloon" class="container" onclick="popBalloon(this.id);"></div>
clicking this item will call the function below
function popBalloon(id){
document.getElementById(id).setAttribute("class","pop");
}
Problem is that I have multiples balloons of the same type, and instead of using a unique id for each one, I would like a way to determine the specific balloon being clicked using the same attribute names.
Is this possible?
If you pass event as the function parameter, you can use event.target to get the clicked Element
function popBalloon (event) {
event.target.setAttribute("class", "pop");
}
div {
margin-top: 10px;
height: 30px;
width: 30px;
border: 1px solid;
border-radius: 50%;
}
.container {
background-color: red;
}
.pop {
background-color: blue;
}
<div class="container" onclick="popBalloon(event);"></div>
<div class="container" onclick="popBalloon(event);"></div>
<div class="container" onclick="popBalloon(event);"></div>
<div class="container" onclick="popBalloon(event);"></div>
<div class="container" onclick="popBalloon(event);"></div>
Most of current answers suggest a function that defines click listener to a group of elements however you asked how to omit unique IDs where there are too many elements in a game. The simple answer is to pass OBJECT instead of ID to the function:
<div class="container" onclick="popBalloon(this);"></div>
and in the function:
function popBalloon(myobj){
myobj.setAttribute("class","pop");
}
Thats all.
Instead of manually entering the function signature in each balloon entry, handle it all in the javascript below. Throw all those balloons into a list. As Scott Hunter suggested, place each balloon in a class. Let's call it "balloon". Then add an event listener to each of those balloons. Here's a quick demo.
var balloonArray = document.querySelectorAll(".balloon");
balloonArray.forEach(function(item) {
item.addEventListener('click', function() {
item.innerText = "Clicked";
});
});
.container {
color: white;
height: 80px;
margin: 10px;
text-align: center;
}
<div class="container balloon" style="background-color: blue">Click me</div>
<div class="container balloon" style="background-color: red">Click me</div>
<div class="container balloon" style="background-color: green">Click me</div>
A good way to do it is add some class to all the balloons. Let's modify your code a bit
<div class="balloon"></div>
<div class="balloon"></div>
<div class="balloon"></div>
I have 3 of those divs with a class of balloon here. For the js we can do
Array.from(document.querySelectorAll(".balloon")).forEach(balloon=>{
balloon.addEventListener('click',()=>{
//On click event here
});
});
Here's how you add a click event to each of the balloon.

Insert HTML or append Child onClick, and remove from previous clicked element

I have a set of div elements inside a container, .div-to-hide is displayed by default whilst .div-to-show is hidden.
When I click in .set, .div-to-hide should hide and .div-to-show should be visible. Next click should return the previous clicked element to its default state.
I need to display to buttons on click inside on .div-to-show.
<div class="container">
<div class="set">
<div class="div-to-hide">Some text</div>
<div class="div-to-show"></div>
</div>
<div class="set">
<div class="div-to-hide">Some text</div>
<div class="div-to-show"></div>
</div>
<div class="set">
<div class="div-to-hide">Some text</div>
<div class="div-to-show"></div>
</div>
</div>
So far I have this:
let lastClicked;
$('.container').on('click', function(e) {
if (this == lastClicked) {
lastClicked = '';
$('.div-to-hide').show();
$(this).children('.div-to-hide').hide();
} else {
lastClicked = this;
$('.div-to-hide').hide();
$(this).children('.div-to-hide').show();
$(this).children('.div-to-show').hide();
}
});
Can't get it to work properly tho.. I don't know what I am missing...
Any help is deeply appreciated!
UPDATE: got it working! Thanks everyone!
First, you are not using delegation (second parameter on the $.on() function) to define the .set element as your this inside the function.
If I understood correctly, you want to show the elements on the last one clicked and hide the rest. You don't really need to know which one you last clicked to do that
$('.container').on('click', '.set', function (e) {
// Now "this" is the clicked .set element
var $this = $(this);
// We'll get the children of .set we want to manipulate
var $div_to_hide = $this.find(".div-to-hide");
var $div_to_show = $this.find(".div-to-show");
// If it's already visible, there's no need to do anything
if ($div_to_show.is(":visible")) {
$div_to_hide.show();
$div_to_show.hide();
}
// Now we get the other .sets
var $other_sets = $this.siblings(".set");
// This second way works for more complex hierarchies. Uncomment if you need it
// var $other_sets = $this.closest(".container").find(".set").not(this);
// We reset ALL af them
$other_sets.find(".div-to-show").hide();
$other_sets.find(".div-to-hide").show();
});
Consider using class toggling instead.
$('.set').on('click', function(e) {
$('.set').removeClass('hidden-child');
$(this).addClass('hidden-child');
});
css:
.hidden-child .div-to-hide, .div-to-show {
display: none;
}
.hidden-child .div-to-show, .div-to-hide {
display: block;
}
This will make your code easier to reason about, and lets css control the display (style) rules.
Edit: changed class name for clarity; expanded explanation; corrected answer to conform to question
Try to make use of siblings() jQuery to hide and show other divs and toggle() jQuery to show and hide itself and also you will need to set click() event on .set, not in .container
$(document).on('click', '.set', function(e) {
$(this).find('.hide').toggle();
$(this).find('.show').toggle();
$(this).siblings('.set').find('.hide').show();
$(this).siblings('.set').find('.show').hide();
});
.show {
display: none;
}
.set div {
padding: 10px;
font: 13px Verdana;
font-weight: bold;
background: red;
color: #ffffff;
margin-bottom: 10px;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="set">
<div class="hide">1 Hide</div>
<div class="show">1 Show</div>
</div>
<div class="set">
<div class="hide">2 Hide</div>
<div class="show">2 Show</div>
</div>
<div class="set">
<div class="hide">3 Hide</div>
<div class="show">3 Show</div>
</div>
</div>

How to detect the ordered position of a class element

Detecting the name of a class is straightforward.
event.target.className
However detecting if a given element is the 3rd, 5th or 11th that uses a particular class is tough, at least for me. I used the console (F12) to find a property I could use but no luck.
In the following simplified example what property or other feature can determine if the user clicked ("box-a")[0] ("box-a")[1] ("box-a")[2] or ("box-a")[3]? I know that I can use individual IDs for each element but I'd rather keep this simple if it is technically possible.
var count;
for (count = 0; count < 4; count++) {
document.getElementsByClassName("box-a")[count].addEventListener("click", checker);
}
function checker() {
document.getElementsByClassName("box-b")[0].innerHTML = event.target.className;
}
// event.target.className targets the classes name, but what property targets the [0], [1], [2] or [3]?
.box-a {
background-color: green;
border: 0.6rem solid black;
padding: 10px;
font-family: arial;
font-size: 4rem;
}
.box-b {
display: block;
background-color: blue;
border: .25rem solid red;
padding: 10px;
font-family: arial;
font-size: 4rem;
}
<div class="box-a">Box 1</div>
<div class="box-a">Box 2</div>
<div class="box-a">Box 3</div>
<div class="box-a">Box 4</div>
<div class="box-b"></div>
When looping over the elements, add an event listener to each box that passes the index of the clicked box to your checker function.
function checker(index) {
// Do whatever you want with the index here
console.log(index)
}
// Add the same event listener to each element, but passing the index of
// the element to the checker function
[].slice.call(document.getElementsByClassName('box-a'))
.forEach(function(element, index) {
element.addEventListener('click', function() { checker(index) })
})
<div class="box-a">Box 1</div>
<div class="box-a">Box 2</div>
<div class="box-a">Box 3</div>
<div class="box-a">Box 4</div>
<div class="box-a">Box 5</div>
This may be not the best solution but it works.
// Click on any div element and see the output
document.querySelectorAll('.box-a').forEach((e) => { // Add the event listener to all the elements with class .box-a
e.addEventListener('click', (event) => {
var element = event.target;
var index = Array.from(element
.parentNode // Get the parent node of the clicked element
.querySelectorAll('.' + element.className)) // Select all the elements inside the parent node (siblings) with the same class name of the clicked element
.indexOf(element) + 1; // Look for the index of the clicked element, + 1
console.log(index);
});
});
Here's a working bin:
JSBin

Click and change THIS div

I have 3 divs with the same class (i can't use IDs on them). I find all of them by targeting their class and then - on click - i want to apply some stuff (e.g. change background-color). i only managed to change all of them, but not only the one i'm actually clicking. what am i missing?
var thisDiv = $('.thisDiv');
thisDiv.click(function() {
var i = thisDiv.index(this);
console.log(i);
console.log(thisDiv.css('background-color'));
// this changes all of the div, not only the clicked one
thisDiv.css('background-color', 'red');
// console msg for the code below: Uncaught TypeError: thisDiv[i].css is not a function
// thisDiv[i].css('background-color', 'red');
// i also tried these, which didn't work...
//console.log(thisDiv[i].css('background-color'));
//console.log(thisDiv.eq[i].css('background-color'));
});
.thisDiv{width:50px;height:50px;background-color:lightgrey;float:left;margin:15px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="thisDiv">div 0</div>
<div class="thisDiv">div 1</div>
<div class="thisDiv">div 2</div>
use $(this) will give you the div which you have clicked
$(this).css('background-color', 'red');
use .eq():
thisDiv.eq(i)
as thisDiv is a collection of objects, you can get the specific ones with $(this) or .eq(i).
var thisDiv = $('.thisDiv');
thisDiv.click(function() {
var i = thisDiv.index(this);
thisDiv.eq(i).css('background-color', 'red');
});
.thisDiv {
width: 50px;
height: 50px;
background-color: lightgrey;
float: left;
margin: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="thisDiv">div 0</div>
<div class="thisDiv">div 1</div>
<div class="thisDiv">div 2</div>

Categories

Resources