Giving a div a style on click - javascript

applying a class to an element only when clicked

You could make 2 different click functions. One for trap and one for the rest.
For that you need to know which ones are the other ( safe ones ). See otherDivsIds in the below code. You find the other id's using the filter function in the idArray and then loop through them ( with forEach or something else ) and add event listeners to each of them.
I would also suggest to ' swap ' the naming of the variables trapBox and trapId. Vice versa would be better
See code below
var idArray = ['one','two','three','four'];
var trapBox = idArray[Math.floor(Math.random() * idArray.length)];
var trapId= document.getElementById(trapBox);
trapId.addEventListener('click', boomClickFunction, false);
var otherDivsIds = idArray.filter(id => id !== trapBox);
otherDivsIds.forEach(id => {
safeBox = document.getElementById(id);
safeBox.addEventListener('click', safeClickFunction, false)
})
var timeoutId = window.setTimeout(ticker, 5000);
function ticker() {
document.getElementById('timesUp').innerHTML = "Time's up!";
document.body.style.backgroundColor = "black";
}
function boomClickFunction() {
this.classList.add('boom')
}
function safeClickFunction() {
this.classList.add('safe')
}
div {
width: 20px;
height: 20px;
background-color: green;
margin: 20px;
float: left;
}
.boom {
background-color: red;
}
.safe {
background-color: lightblue;
}
#timesUp {
color: white;
}
<div id='one'>
</div>
<div id='two'>
</div>
<div id='three'>
</div>
<div id='four'>
</div>
<span id="timesUp">
</span>

You can add a class to an element by using classList.add('classToBeAdded').
In your case, you could put it in your clickFunction:
trapId.classList.add('boom');

Related

JavaScript delete modal onclick and decrease counter

I want to make a basic inbox function. It contains 3 messages.
So I want to make that when the user click onto the DELETE button, set the msg1's display to none, and decrease the messages value.
Here is the example code:
var x = 2;
function deleteMsg1() {
var msg1 = document.getElementsByClassName("cont");
if (confirm("Are you sure to want to delete this message?")) {
msg1[0].style.display = "none";
x = x-1;
} else {
}
}
function deleteMsg2() {
var msg2 = document.getElementsByClassName("cont2");
if (confirm("Are you sure to want to delete this message?")) {
msg2[0].style.display = "none";
x = x-1;
} else {
}
}
document.getElementById("msgcount").innerHTML = x;
.cont, .cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span>messages</h1>
<button onclick="deleteMsg1()">Delete</button>
<div class="cont">
Some text...
</div>
<br><br>
<button onclick="deleteMsg2()">Delete</button>
<div class="cont2">
Some text...
</div>
I know this isn’t the best idea, but I guess it’s bad.
I think I should do this with one function() and try something event listener but I don't really know how to do that.
Any idea or help?
You should wrap each message's HTML in a parent element so that you can then treat each set of elements that comprise a message as a single unit and delete it all at once.
To be able to do this with a single function, you can use this to reference the element that triggered the callback function in the first place and .closest() to access the single parent wrapper.
Notes:
Do not use inline HTML event attributes, like onclick.
Separate your HTML and your JavaScript and use .addEventListener()
to bind elements to event callbacks. Even MDN recommends not using
them.
Do not use .getElementsByClassName() as it is a 25+ year old
API that has significant performance implications. Instead, use the
modern .querySelectorAll() method.
Do not use .innerHTML if you can avoid it as it has security and
performance implications. Since the text you are wanting to update
doesn't have any HTML in it anyway, .innerHTML is not warranted.
Instead, use .textContent.
// Do your event binding in JavaScript, not HTML
document.querySelectorAll("button").forEach(function(element){
element.addEventListener("click", function(){
if (confirm("Are you sure to want to delete this message?")) {
// All you need to do is delete the nearest complete
// ancestor message construct, which can be done with
// the .closest() method
this.closest(".message").remove();
updateMessageCount();
}
});
});
function updateMessageCount(){
// Set the count equal to the length of the
// collection returned by searching for all the
// messages
document.getElementById("msgcount").textContent =
document.querySelectorAll(".message").length;
}
updateMessageCount();
.cont, .cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span> messages</h1>
<!-- By wrapping each message, you can treat all its HTML
as one single unit. -->
<div class="message">
<button>Delete</button>
<div class="cont">
Some text...
</div>
</div>
<br><br>
<div class="message">
<button>Delete</button>
<div class="cont">
Some text...
</div>
</div>
Explained
Here's a simple enough solution, you need to update the HTML manually every time you want to update the value of x. That's why I created an updateX function, it'll just take the value & update the DOM, it's quite that simple.
const updateX = (x) => {
document.getElementById("msgcount").innerHTML = x;
};
let x = 2;
const del = (className) => {
const msg = document.getElementsByClassName(className);
if (confirm("Are you sure to want to delete this message?")) {
msg[0].style.display = "none";
x--;
} else {
console.log("===");
}
updateX(x);
};
updateX(x);
.cont,
.cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span>messages</h1>
<button onclick="del('cont')">Delete</button>
<div class="cont">
Some text...
</div>
<br/><br/>
<button onclick="del('cont2')">Delete</button>
<div class="cont2">
Some text...
</div>
My advice to you: Never declare events js inside html structure tags! As here:
<button onclick="deleteMsg1()">Delete</button>
This is a very bad practice. This has many disadvantages. And this can lead to bad consequences.
I made a solution for you with the forEach() method, without using javascript in html.
The Delete button is also removed.
let msg = document.querySelectorAll(".cont");
let btn_del = document.querySelectorAll('.btn_del');
let x = 2;
btn_del.forEach(function (btn_del_current, index) {
btn_del_current.addEventListener('click', function () {
if (confirm("Are you sure to want to delete this message?")) {
this.style.display = "none";
msg[index].style.display = "none";
x = x - 1;
document.getElementById("msgcount").innerHTML = x;
} else {}
});
});
.cont, .cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span>messages</h1>
<button class="btn_del">Delete</button>
<div class="cont">
Some text...
</div>
<br><br>
<button class="btn_del">Delete</button>
<div class="cont">
Some text...
</div>

How to add eventlistener to dynamically created divs

How to add event delegation to dynamically created divs, to change property of the target div? I've tried several suggestions that I found for event delegation but none of them work. I think I'm making some mistakes but I don't know how to fix.
I am trying to develop a file thumbnail list interface with HTML and JavaScript. I made a method that draws thumbnails dynamically from an Array. And now I want to add some functions to manipulate the thumbnails, ex. changing border color of the item(div) when it is clicked.
First I tried loop-method to add event listeners to the divs, but it didn't work well. And now I learned that event delegation is better way to add event listeners to dynamically created elements. But the problem is that though I'v tried codes but they didn't work at all.
I think I am making some mistakes or mis-using methods but I don't know what is the problem.
JavaScript
function drawThumbnails(area, list){
var j
var createdList = []
for (j=0; j<list.length; j++){
var thmb = document.getElementById("fileThumb");
var name = document.getElementById("itemName");
var date = document.getElementById("itemDate");
var thmbimg = document.getElementById("fileThumbImage");
var thmbicon = document.getElementById("file_icon_thumb");
name.innerHTML=list[j][0];
date.innerHTML=list[j][1];
if (list[j][2] == "folder"){
thmbimg.src = "thmb_folder.png";
thmbicon.style.display = "none";
}
else {
if (list[j][2] == "img"){
thmbimg.src=getthmbimgsample();
}
else{
thmbimg.src = getThmbimg(list[j][2]);
}
thmbicon.style.display = "block";
thmbicon.src = getThmbicon(list[j][2]);
}
var cln = thmb.cloneNode(true);
cln.style.display = "block";
document.getElementById(area).append(cln);
createdList.push(cln);
}
thmbLists.push(createdList);
}
drawThumbnails("folderArea", folders);
drawThumbnails("fileArea", files);
document.getElementById("folderArea").addEventListener('click',function(e){
if(e.target && e.target.className == "fileThumb"){
e.target.style.borderColor = "#408CFF";
}
});
HTML
<body>
<div class = "contentArea" id="contentArea">
<div class = "thumbArea" id="folderArea">
<div class = "fileThumb" id="fileThumb">
<img src="icon_thumb_folder.png" class="fileThumb_normal" id="fileThumbImage">
<div class="fileName">
<img src="icon_thumb_file.png" style="width: 20px;" id="file_icon_thumb">
<div class="fileNameLine" id = "itemName">File/FolderName</div>
<div class="fileNameDate" id="itemDate">Date</div>
</div>
</div>
</div>
<div class = "contentAreaSectionHeader">
<input type="checkbox" id="chTest2" name="chTest2">
<label for="chTest2"><span>Files</span></label>
</div>
<div class = "thumbArea" id="fileArea">
</div>
</body>
CSS
.fileThumb{
width: 213px;
height: 183px;
border-radius: 2px;
border-style: solid;
border-width: 1px;
border-color: #EEEEEE;
text-align: center;
position: relative;
float:left;
margin: 18px;
display: none;
overflow: hidden;
}

JavaScript for changing a <div> colour from a button press

I'm a little unsure why my code doesn't seem to be working when my html and JS code are within the same file. When the html and JS are separate, seems to be working fine. Can someone point out the error in my ways....I'm a newbie!!
HTML:
<div class="main">
<div class="light"></div>
<button onclick="chngCol()" id="burn">Burn!</button>
</div>
JavaScript:
chngCol() {
if(document.getElementByClass('light').style.background == "#00ffff")
{
document.getElementByClass('light').style.background = "#ffff00";
}
else if(document.getElementByClass('light').style.background == "ffff00")
{
document.getElementByClass('light').style.background = "#ff00ff";
}
else if(document.getElementByClass('light').style.background == "#ff00ff")
{
document.getElementByClass('light').style.background = "#00ffff";
}
}
CSS:
.light{
width: 50px;
height: 50px;
background-color:#00ffff;
}
All code is in the same document with the appropriate tags and however the error i'm getting in Chrome Console on the first { after calling chngCol.
There are a multitude of issues.
chngCol() { is not valid JS. Either function chngCol() { OR const chngCol = () =>
You need document.getElementsByClassName("light")[0] OR better, document.querySelector(".light")
You cannot read the background color of the element if it is not set in script first.
I think you meant to do this:
let cnt = 0;
const colors = ["#00ffff", "#ffff00", "#ff00ff"];
const chngCol = () => {
cnt++;
if (cnt >= colors.length) cnt = 0; // wrap
document.querySelector('.light').style.background = colors[cnt]; // use the array
}
document.getElementById("burn").addEventListener("click", chngCol);
.light {
width: 50px;
height: 50px;
background-color: #00ffff;
}
#burn {
width: 150px;
font-weight: 700;
}
<div class="main">
<div class="light"></div>
<button id="burn">Burn!</button>
</div>
The document.getElementByClass selector is an array selector. In order to select your element you should select the first element of the array.
Try this instead:
document.getElementsByClassName('light')[0].style.background

Change classes only for the child clicked within the parent using JavaScript

I have two div's within a parent div. I need to change the classes for the child div which I clicked. For that I am writing a method to check which child was clicked and respectively I am trying to hide the other child div.
But I am not able to add classes or remove classes since the index is showing always as undefined. I am feeling there is some problem with the return statement.
function changeClass() {
const list = document.getElementById('my_div').children;
const indx = this.getIndexOfParent(list);
for (let i = 0; i < list.length; i++) {
if (indx === 0) {
list[indx + 1].classList.add("d-none d-sm-block");
list[indx].classList.remove("col-6 d-none d-sm-block");
} else if (indx === 1) {
list[indx - 1].classList.add("d-none d-sm-block");
list[indx].classList.remove("col-6 d-none d-sm-block");
}
list[indx].classList.add("d-xs-block");
}
}
function getIndexOfParent(child_list) {
for (var i = 0, len = child_list.length; i < len; i++) {
((index) => {
child_list[i].onclick = () => {
return index;
};
})(i);
}
}
.row {
background: #f8f9fa;
margin-top: 20px;
}
.row > div {
border: solid 1px black;
padding: 10px;
}
<div class="container">
<div class="row">
<div onclick="changeClass()" class="col-md-6 col-6">
child-div-1
</div>
<div onclick="changeClass()" class="col-md-6 col-6">
child-div-2
</div>
</div>
</div>
All I want is that, when I click on child-div-1 it should hide child-div-2 and vice versa only for small screens (which is why I am handling it by col-6 and d-xs-block classes)
Can anyone help me to solve the below problem.
You have added onclick within the for loop. Instead add the class to the clicked child div and remove the class from it's sibling div.
document.querySelectorAll('div.row > div')
.forEach((div) => {
div.addEventListener('click', function({
target
}) {
target.classList.add('d-none', 'd-sm-block');
const sibDiv = Array.prototype.filter.call(target.parentNode.children, div => div != target)[0];
sibDiv.classList.remove('col-6', 'd-none', 'd-sm-block');
});
});
.row {
background: #f8f9fa;
margin-top: 20px;
}
.row>div {
border: solid 1px black;
padding: 10px;
}
<div class="container">
<div class="row">
<div class="col-md-6 col-6">
child-div-1
</div>
<div class="col-md-6 col-6">
child-div-2
</div>
</div>
</div>
-- Edit --
The return statement will return the value of index to the callback function, you also need to add return to the callback function, so whatever result the callback function get will return to the function getIndexOfParent.
function getIndex() {
let i = 0;
((index) => { // No return, logs undefined
return index;
})(i);
}
console.log(getIndex());
function getIndex() {
let i = 0;
return ((index) => { // with return
return index;
})(i);
}
console.log(getIndex());
I made a pen for solving this problem.
Check the pen here
the solution is easy you simply have to write this line
e.stopPropagation();
this will stop the event from triggering on parent divs
basically what you are describing is called event bubbling.
you can read about it more on medium

jQuery - prev/next navigation between non-siblings

I have a bunch of elements of the same type that have different parents, but I would like to be able to seamlessly navigate/cycle through all of them as if they were together.
<div>
<a href="#" class="open></a>
</div>
<div>
</div>
<div>
</div>
‹
›
I've managed to get this far: https://jsfiddle.net/pj0ecxge/
Currently it doesn't function as intended, as prev() and next() are only meant to target sibling elements, so the arrows don't work if the previous or next element is in another parent.
A single element will always be open by default, but it won't always be the same element as shown in the example. Also, only one element can be open at the same time.
If it makes a difference, I can add a single class to all children elements, but I can't change the HTML structure i.e put them all inside the same parent.
It would be nice if the navigation is infinite - i.e clicking next while the last element is open will show the first element and vice versa, but this is not required if it's too complex to do.
Thanks in advance and any help will be very appreciated!
You can check whether there are next/previous elements, if not then you can move a layer up/down like
$('.prev').click(function(e) {
e.preventDefault();
var current = $('.open');
var prev = current.prev();
if (!prev.length) {
prev = current.parent().prev('div').children('a:last-child')
}
if (prev.length) {
current.removeClass('open');
prev.addClass('open');
}
});
$('.next').click(function(e) {
e.preventDefault();
var current = $('.open');
var next = current.next();
if (!next.length) {
next = current.parent().next('div').children('a:first-child')
}
if (next.length) {
current.removeClass('open');
next.addClass('open');
}
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
text-align: center;
}
div {
font-size: 0;
}
div a {
width: 150px;
height: 150px;
border: 2px solid black;
}
a {
display: inline-block;
}
.open {
background: red;
}
.prev,
.next {
font-size: 100px;
text-decoration: none;
margin: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
</div>
<div>
</div>
<div>
</div>
‹
›
Find the next set when the current set has reached either end. And the if the set is the last one then go back to the first one (and vice-versa).
$('.prev').click(function(e) {
e.preventDefault();
var current = $('.open');
var prev = current.prev();
if (!prev.length) {
prev = current.parent().prev('div').children('a:last-of-type');
if (!prev.length) {
prev = $('div:last-of-type').children('a:last-of-type');
}
}
current.removeClass('open');
prev.addClass('open');
});
$('.next').click(function(e) {
e.preventDefault();
var current = $('.open');
var next = current.next();
if (!next.length) {
next = current.parent().next('div').children('a:first-of-type');
if (!next.length) {
next = $('div:first-of-type').children('a:first-of-type');
}
}
current.removeClass('open');
next.addClass('open');
});

Categories