I have to toggle classes of buttons and parent element (cards)
let btns = document.querySelectorAll('.btn-primary');
btns.forEach(btn => {
btn.addEventListener('click', function(e){
e.target.parentElement.classList.toggle('red');
e.target.classList.toggle('green');
});
});
But, actually, the card and button does not change the class at the same time. Card gets red color but button gets green after I click another button.
You can extend click function a bit and decide if all buttons should also contain green class
let btns = document.querySelectorAll('.btn-primary');
btns.forEach(btn => {
btn.addEventListener('click', function(e) {
const parentElement = e.target.parentElement;
const element = e.target;
for (let button of document.querySelectorAll('.btn-primary')) {
if(button === element){
continue
}
if (button.classList.contains('green')) {
button.classList.toggle('green');
}
}
element.classList.toggle('green');
if([...document.querySelectorAll('.btn-primary')].some(element => element.classList.contains('green'))) {
parentElement.classList.add('red');
}
else {
parentElement.classList.remove('red');
}
});
});
.parent {
padding: 1rem;
border: 1px solid black;
}
.parent.red {
border-color: red;
}
.green {
color: green;
}
.red {
color: red;
}
<div class="parent">
<button class="btn-primary">Test</button>
<button class="btn-primary">Test</button>
</div>
Related
I have several identical divs and each of them contains a button that is hidden. I want to make button visible when you hover on the parent div. I wrote this code:
const cardElements = document.querySelectorAll('.middle_section__president_section');
const learnButtons = document.querySelectorAll('.president_section__button');
cardElements.forEach((cardElement) => {
cardElement.addEventListener('mouseover', () => {
learnButtons.forEach((learnButton) => {
learnButton.style.height = "50px";
learnButton.style.opacity = "1";
learnButton.style.border = "3px solid rgb(129, 129, 129)";
});
});
cardElement.addEventListener('mouseout', () => {
learnButtons.forEach((learnButton) => {
learnButton.style.height = "0px";
learnButton.style.opacity = "0";
learnButton.style.border = "0px solid rgb(129, 129, 129)";
});
});
})
carElements is parent, learnButtons - child.
but with this code when i hover on one div buttons appears in every similiar div. How can i make button appear only on hovered div?
Use the Event object
cardElement.addEventListener('mouseover', () => {
learnButtons.forEach((learnButton) => {
convert this to
cardElement.addEventListener('mouseover', (e) => {
var learnButton = e.target;
There's no need to use JS for this. As Mister Jojo/traktor pointed out in their comments you can use the CSS :hover pseudo-class instead.
The key CSS line is .box:hover button { visibility: visible;} which means "when you hover over the parent container make its button visible".
.box { width: 50%; display: flex; flex-direction: column; border: 1px solid lightgray; margin: 0.25em; padding: 0.25em;}
button { visibility: hidden; margin: 0.25em 0; border-radius: 5px; background-color: lightgreen; }
.box:hover button { visibility: visible;}
.box:hover, button:hover { cursor: pointer; }
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
<section class="box">
Some text
<button>Click for a surprise!</button>
</section>
It is bad practice to iterate over all elements and give each an event, as you can add 1 event handler to the parent and when the event happens you can check the affected element by the event parameter in the handler call back
parent.addEVentListener('mouseover', (e) => {
if(e.target.classList.contains('middle_section__president_section')) {
// Do
}
});
I just started school, and this is my first question ever asked on Stackoverflow, so I apologize up front regarding both formatting and wording of this question.
I want to change the border color of my div to a style I have already declared when I click on it. To show that this has been selected.
I have three divs with id="red/green/pink".
Now, is there a way to change this function to grab information from the div I clicked, so I dont have to write 3 (almost) identical functions?
.chosenBorder{
border: 3px solid gold;
}
<div id="red" class="mainDivs" onclick="newColor('red')">Red?</div>
<div id="green" class="mainDivs" onclick="newColor('green')">Green?</div>
<div id="pink" class="mainDivs" onclick="newColor('pink')">Pink?</div>
<div class="mainDivs" onclick="whatNow(changeBig)">Choose!</div>
<script>
let changeBig = "";
let chosenDiv = document.getElementById("body");
function newColor(thisColor) {
changeBig = thisColor;
// something that make this part dynamic.classList.toggle("chosenBorder");
}
function whatNow(changeBig) {
document.body.style.backgroundColor = changeBig;
}
</script>
Since you already have an id contains the name of color; get the advantage of it: and keep track of the selected color in your variable changeBig.
let changeBig = "";
function newColor(div) {
// initial all divs to black
initialDivs();
div.style.borderColor = div.id;
changeBig = div.id;
}
function initialDivs() {
[...document.querySelectorAll('.mainDivs')].forEach(div => {
div.style.borderColor = 'black'
});
}
function whatNow() {
document.body.style.backgroundColor = changeBig;
}
.mainDivs {
padding: 10px;
margin: 10px;
border: 3px solid;
outline: 3px solid;
width: fit-content;
cursor: pointer;
}
<div id="red" class="mainDivs" onclick="newColor(this)">Red?</div>
<div id="green" class="mainDivs" onclick="newColor(this)">Green?</div>
<div id="pink" class="mainDivs" onclick="newColor(this)">Pink?</div>
<div class="mainDivs" onclick="whatNow()">Choose!</div>
There are a few (modern) modifications you can make to simplify things.
Remove the inline JS.
Use CSS to store the style information.
Use data attributes to store the colour rather than the id.
Wrap the div elements (I've called them boxes here) in a containing element. This way you can use a technique called event delegation. By attaching one listener to the container you can have that listen to events from its child elements as they "bubble up" the DOM. When an event is caught it calls a function that 1) checks that the event is from a box element 2) retrieves the color from the element's dataset, and adds it to its classList along with an active class.
// Cache the elements
const boxes = document.querySelectorAll('.box');
const container = document.querySelector('.boxes');
const button = document.querySelector('button');
// Add a listener to the container which calls
// `handleClick` when it catches an event fired from one of
// its child elements, and a listener to the button to change
// the background
container.addEventListener('click', handleClick);
button.addEventListener('click', handleBackground);
function handleClick(e) {
// Check to see if the child element that fired
// the event has a box class
if (e.target.matches('.box')) {
// Remove the color and active classes from
// all the boxes
boxes.forEach(box => box.className = 'box');
// Destructure the color from its dataset, and
// add that to the class list of the clicked box
// along with an active class
const { color } = e.target.dataset;
e.target.classList.add(color, 'active');
}
}
function handleBackground() {
// Get the active box, get its color, and then assign
// that color to the body background
const active = document.querySelector('.box.active');
const { color } = active.dataset;
document.body.style.backgroundColor = color;
}
.boxes { display: flex; flex-direction: row; background-color: white; padding: 0.4em;}
.box { display: flex; justify-content: center; align-items: center; width: 50px; height: 50px; border: 2px solid #dfdfdf; margin-right: 0.25em; }
button { margin-top: 1em; }
button:hover { cursor: pointer; }
.box:hover { cursor: pointer; }
.red { border: 2px solid red; }
.green { border: 2px solid green; }
.pink { border: 2px solid pink; }
<div class="boxes">
<div class="box" data-color="red">Red</div>
<div class="box" data-color="green">Green</div>
<div class="box" data-color="pink">Pink</div>
</div>
<button>Change background</button>
I have this script but need to have the class to be changed to "go" or "stop". currently I can turn both to change to the class but it should change to one or the other
Code
var form = document.querySelector("form");
form.addEventListener("click", function(event) {
event.preventDefault();
const classId = event.target.id;
if (classId == "go") {
event.target.className = "go";
} else if (classId == "stop") {
event.target.className = "stop";
}
});
.go {
background: green;
color: white;
}
.stop {
background: red;
color: white;
}
<form action="">
<button id="go">GO!</button>
<button id="stop">STOP!</button>
</form>
You're adding the class to the clicked button, but never removing the class from the other button.
var form = document.querySelector("form");
const goButton = document.querySelector("#go");
const stopButton = document.querySelector("#stop");
form.addEventListener("click", function(event) {
event.preventDefault();
if (event.target == goButton) {
goButton.classList.add("go");
stopButton.classList.remove("stop");
} else if (event.target == stopButton) {
stopButton.classList.add("stop");
goButton.classList.remove("go");
}
});
.go {
background: green;
color: white;
}
.stop {
background: red;
color: white;
}
<form action="">
<button id="go">GO!</button>
<button id="stop">STOP!</button>
</form>
How can I turn an element like this:
Element1
Element2
Element3
To be like a selected button, for example, Its normal look be
.select {
border: 1px solid red;
}
But if I clicked on one element of them it turn to be
.select {
background-color: red;
}
But the trick I want to learn here is, How can I make it only one element being able to have the style, Like a radio buttons, Only one button to have the selected style, and if I clicked on another button, the style be removed from the previous one and be at the clicked one, Using JavaScript and CSS only if possible
//get all buttons
var btns = document.getElementsByClassName("select");
function clicker() {
//loop through all buttons
for (y = 0; y < btns.length; ++y) {
//if button is not the current button remove the background class
if (btns[y].classList.contains && btns[y] != this) {
btns[y].classList.remove("colorize")
} //end if
//add background class to current button
this.classList.add("colorize");
}
}
//add an event handler to all buttons
for (x = 0; x < btns.length; ++x) {
btns[x].addEventListener("click", clicker)
}
.select {
border: 1px solid red;
}
.colorize {
background-color: red;
}
Element1
Element2
Element3
You can try this:- First, remove selected class from all the links and then add selected class to that clicked link (using jQuery).
HTML
Element1
Element2
Element3
CSS
.select {
border: 1px solid red;
}
.selected {
background-color: red;
}
jQuery
$(document).ready(function(){
$('.select').click(function(){
$('.select').removeClass('selected');
$(this).addClass('selected');
});
})
Live Example
You can do this quite easily using JavaScript and the addClass() method.
Firstly, don't use the same ID for multiple elements.
HTML:
Element1
Element2
Element3
CSS:
.select {
border: 1px solid red;
}
.clicked {
background-color: red;
}
JavaScript:
$(document).ready(function () {
$(".select").click(function () {
$(".select").addClass("clicked");
});
});
Note this method uses jQuery
To get a better idea what i'm doing look here for my previous code that i try to make a little better >>Codepen
I want to have an array that i fill up with all the id's that i try to animate and with one function toggle the classes .open .closed on every id in the array.
so on an click add .open to #Hamburger, #Navigation, #Black-filter. and one second click remove .open and add .closed for those id's.
because i'm still learning javascript i want it to work in vanilla javascript so i understand the basics before im going on with jquery.
var hamburger = document.getElementById('Hamburger');
var navigation = document.getElementById('Navigation');
var blackFilter = document.getElementById('Black-filter');
var isOpen = true; // true or false
var animation = [h, s, b]; // #H #S #B
var open = "open"; // .open
var closed = "closed"; // .closed
function trigger() {
if (isOpen === true) {
animation.classList.add(open); // add .open to all id's
animation.classList.remove(closed); // remove .closed from all id's
} else {
animation.classList.add(closed);
animation.classList.remove(open);
}
isOpen = !isOpen; // toggles true to false
}
hamburger.addEventListener('click', trigger, false); // onclick toggle class
blackFilter.addEventListener('click', trigger, false); // onclick toggle class
body {
width: 100%;
}
#Hamburger {
height: 100px;
background: red;
width: 100px;
}
#Hamburger.open {
opacity: 0.5;
}
#Hamburger.closed {
opacity: 1;
}
#Navigation {
height: 100px;
background: blue;
width: 100px;
}
#Navigation.open {
opacity: 0.5;
}
#Navigation.closed {
opacity: 1;
}
#Black-filter {
height: 100px;
background: green;
width: 100px;
}
#Black-filter.open {
opacity: 0.5;
}
#Black-filter.closed {
opacity: 1;
}
<body>
<div id="Hamburger"></div>
<div id="Navigation"></div>
<div id="Black-filter"></div>
</body>
What you are looking for is:
var isOpen = true;
var hamburger = document.getElementById('Hamburger');
var navigation = document.getElementById('Navigation');
var blackFilter = document.getElementById('Black-filter');
var animatable = [hamburger, navigation, blackFilter];
var openClass = "open"; // .open
var closedClass = "closed"; // .closed
function trigger() {
if (isOpen) {
animatable.forEach(function (element) {
element.classList.add(openClass);
element.classList.remove(closedClass);
});
} else {
animatable.forEach(function (element) {
element.classList.add(closedClass);
element.classList.remove(openClass);
});
}
isOpen = !isOpen;
}
hamburger.addEventListener('click', trigger, false);
blackFilter.addEventListener('click', trigger, false);
Demo
There are a few things that need improvement.
First of all you are naming you variables rather poorly. Which is actually already one of your problems, first you say that
var b = document.getElementById('B');
and then later
var b = "closed";
So this needs to be fixed, use variable names that are descriptive so you will know what you are talking about when.
Last but not least you are trying to change the elements of that array a, not the array itself. So you need to access the elements by themselves, set their classes and then you are good to go e.g.:
for( var index in a ) {
if ( open === true ) {
a[index].classList.add(b);
a[index].classList.remove(c);
} else {
a[index].classList.add(c);
a[index].classList.remove(b);
}
open = !open;
Firstly ou don't need "open" AND "close" classes, only one would clearly simplify your code (and there is the "default" state).
Then, add a class for all your buttons, the easily manipulate them in JS and CSS (here the class ".btn");
// Directly get on array (a NodeList more precisely)
var buttons = document.getElementsByClassName('btn');
function toggleClass() {
// Loop to add or remove (toggle) the the '.open' class
for (var i=0; i<buttons.length; i++) {
buttons[i].classList.toggle('open');
}
}
// Loop to add event listener to all buttons
for (var i=0; i<buttons.length; i++) {
buttons[i].addEventListener('click', toggleClass, false);
}
.btn {
height: 100px;
width: 100px;
}
.btn.open {
opacity: 0.5;
}
#Hamburger { background: red; }
#Navigation { background: blue; }
#Black-filter { background: green; }
<div id="Hamburger" class="btn"></div>
<div id="Navigation" class="btn"></div>
<div id="Black-filter" class="btn"></div>
This is already way simpler. But you should have a parent element holding the opened/closes state, so you wouldn't loop in an array.
// Only need to manipulate one DOM node
var menu = document.getElementById('menu');
function toggleClass() {
menu.classList.toggle('open');
}
menu.addEventListener('click', toggleClass, false);
body {
width: 100%;
}
.btn {
height: 100px;
width: 100px;
}
.menu.open > .btn {
opacity: 0.5;
}
#Hamburger { background: red; }
#Navigation { background: blue; }
#Black-filter { background: green; }
<div class="menu" id="menu">
<div id="Hamburger" class="btn"></div>
<div id="Navigation" class="btn"></div>
<div id="Black-filter" class="btn"
</div>
Your event listener gets the event as the 1st argument. Use it to decide what to do:
function trigger(event) {// use event.target ... }