I'm having problem with removing a class from an element. I've tried it many ways, but still it won't work. What could the problem be?
Thanks!
function boxClick(e) {
e.currentTarget.classList.add("valami");
e.currentTarget.setAttribute("id", "currentBox");
}
function closeBox() {
var openedBox = document.getElementsByClassName("valami");
var curBox = document.getElementById("currentBox");
curBox.classList.remove("valami");
}
var gridBoxok = document.getElementsByClassName("grid-box-content");
for (var i = 0; i < gridBoxok.length; i++) {
gridBoxok[i].addEventListener('click', boxClick, false);
}
var close = document.getElementsByClassName("close-container");
for (var i = 0; i < close.length; i++) {
close[i].addEventListener('click', closeBox, false);
}
.valami {
outline: solid yellow 1px;
}
<div class="grid-container">
<div class="grid-box">
<div class="grid-box-content">
<div class="close-container">
fdfadsf
<i class="fas fa-times"></i>
</div>
</div>
</div>
</div>
You just need to stop event bubbling in close event handler, otherwise after closeBox (removes class) event keeps propagating up the DOM tree and when it reaches .grid-box-content it causes boxClick (add class) execute again.
Try this:
function closeBox(e) {
e.stopPropagation(); // <--- add this line
var openedBox = document.getElementsByClassName("valami");
var curBox = document.getElementById("currentBox")
curBox.classList.remove("valami");
}
Demo: https://jsfiddle.net/cy5ukzcg/
I think the way you are binding your close is incorrect, I would do it like below. Also .add and .remove don't work in certain browsers so I changed the way that the class was added and removed:
function boxClick(e) {
e.currentTarget.classList += " valami";
e.currentTarget.removeEventListener('click', boxClick); // remove box click
e.currentTarget.addEventListener('click', closeBox); // bind close click
}
function closeBox(e) {
e.currentTarget.classList = e.currentTarget.className.replace(" valami", "");
e.currentTarget.removeEventListener('click', closeBox); // remove close click
e.currentTarget.addEventListener('click', boxClick); // bind box click
}
var gridBoxok = document.getElementsByClassName("grid-box-content");
for (var i = 0; i < gridBoxok.length; i++) {
gridBoxok[i].addEventListener('click', boxClick);
}
.valami {
outline: solid yellow 1px;
}
<div class="grid-container">
<div class="grid-box">
<div class="grid-box-content">
<div class="close-container">
fdfadsf
<i class="fas fa-times"></i>
</div>
</div>
</div>
</div>
Edit, sorry, didn't realise the close binding was on a different element within the parent. So close binding was correct, but you needed to stop propagation of click like in dfsq's answer. Will leave this though as an alternate way of updating class list (in case you need to support ie)
Related
When any element with .mytrigger is clicked, .myactive will be toggled on element with #mytarget.
I have the following code:
var navclick = document.getElementsByClassName("mytrigger");
for (var i = 0; i < navclick.length; i++) {
navclick[i].onclick = function() {
document.getElementById('mytarget').classList.toggle("myactive");
}
}
.myactive {
background-color: blue;
color: white;
}
<a class="mytrigger">Button</a>
<div id="mytarget"><p>Hello</p></div>
<a class="mytrigger">Button</a>
I need to have multiple triggers and from that this became confusing so I am unable to figure out the correct code. I can't use jquery for this.
Make as many as elements you want with class ".mytrigger" Just put onclick function as mentioned.
I hope this helps:-
If not then please clarify your problem
HTML CODE
<a onclick="myFunction()" class="mytrigger">Button</a>
<div id="mytarget"><p>Hello</p></div>
<a onclick="myFunction()" class="mytrigger">Button</a>
Javascript CODE
function myFunction() {
var element = document.getElementById("mytarget");
element.classList.toggle("myactive");
}
Using your code, I just changed document.getElementsById to document.getElementById (removing the s).
var navclick = document.getElementsByClassName("mytrigger");
for (var i = 0; i < navclick.length; i++) {
navclick[i].onclick = function() {
document.getElementById("mytarget").classList.toggle('myactive');
}
}
.myactive {
background-color: blue;
color: white;
}
<button class="mytrigger">Button
</button>
<div id="mytarget"><p>Hello</p>
</div>
<button class="mytrigger">Button
</button>
Using addEventListener:
It sets up a function that will be called whenever the specified event is delivered to the target.
document.getElementsByClassName('mytrigger').addEventListener('click', function() {
document.getElementById('mytarget').classList.toggle("myactive");
});
Using document.bind:
document.bind('click', '.mytrigger', function(){
document.getElementById('mytarget').classList.toggle("myactive");
});
This question was quite hard to summarize in the title, but what I have is a group of elements with the class panel. When I click a panel, I add a class of open to it. What I also want to do is remove the open class if another panel already has the open class.
Here is the code:
const panels = document.querySelectorAll('.panel');
function toggleOpen() {
this.classList.toggle('open');
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
Right now I can add the open class to however many panels I want, but I only want one panel to have the open class at a time.
Any help no how to achieve this?
The most efficient way is cache the DOM node is currently selected:
const panels = document.querySelectorAll('.panel');
let openedPanel = null;
function toggleOpen() {
if (openedPanel)
openedPanel.classList.remove('open');
this.classList.add('open');
openedPanel = this;
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
As was mentioned, it would be more efficient also delegate the event, so if all the panels share some ancestor, you should add the event listener to that ancestor, and then from the event listener doing something like:
toggleOpen({target}) {
const panel = target.closest('.panel')
if (openedPanel)
openedPanel.classList.remove('open');
panel.classList.add('open');
openedPanel = panel;
}
But as said they need to share a common ancestor.
Because you only want one opened at a time. You can directly target that element by getting the elements with class open, targeting the first element and removing class open before you add it to the selected one.
let opened = document.getElementsByClassName('open')[0];
if(opened!=undefined)
opened.classList.toggle('open');
This way you dont have to loop or save an extra global variable.
const panels = document.querySelectorAll('.panel');
function toggleOpen() {
let opened = document.getElementsByClassName('open')[0];
if(opened!=undefined)
opened.classList.toggle('open');
this.classList.toggle('open');
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen));
.panel {
width: 50px;
height: 50px;
margin: 1px;
background-color: aquamarine;
}
.open {
background-color: tomato;
}
<div class="panel"></div>
<div class="panel"></div>
<div class="panel"></div>
var doc = document;
var panelButtons = doc.querySelectorAll(".panel");
for (var i = 0; i < panelButtons.length; i++) {
panelButtons[i].addEventListener("click", function (evt) {
clearBlueFromButtons();
evt.target.classList.add("blue");
});
}
function clearBlueFromButtons(){
for (var i = 0; i < panelButtons.length; i++) {
panelButtons[i].classList.remove("blue");
}
}
.blue{
background: blue;
}
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
<button class="panel">click me</button>
You can set the reference of the last opened panel in a variable and then remove the class name "open" when opening another panel, below an exemple:
// select all panels
const panels = document.querySelectorAll('.panel');
// define variable for the last clicked panel
let lastOpenedPanel;
/*
* Add the open class name for the current panel and remove it from the previous one
*/
function toggleOpen(
{
this.classList.toggle('open');
setLastOpenedTab(this);
}
/*
* Set the last opened tab and remove the open class from the previous one
*/
function setLastOpenedTab(context) {
if(lastOpenedPanel){
lastOpenedPanel.classList.remove('open');
}
lastOpenedPanel = context;
}
panels.forEach(panel => panel.addEventListener('click', toggleOpen))
I recommend the use of javascript module pattern to better organize and share your functions
I recommend also the use of Jsdoc to better add documentation to your javascript code
Note that the property "classList" is not supported by IE9:
https://www.w3schools.com/howto/howto_js_toggle_class.asp
Try adding these lines BEFORE “this.classList.toggle” in your toggleOpen function:
for (var i = 0; i < panels.length; i++){
panels[i].classList.remove(“active”);
}
Use an if statement to check if the element has "open" and "panel" then remove the open class. Below is the pseudo code:
if ((element.classList.contains(open)) == True && (element.classList.contains(panel))){
element.classList.remove("open");
}
Hi guys I have written the following code in order to be able to toggle a class on and off an element on click.
The element:
<h4 class="swatch-label-size swatch__label--error">test</h4>
The functionality:
function newFunctionTest() {
var termsToggles = document.querySelectorAll('.swatch-label-size');
for (var i = 0; i < termsToggles.length; i++) {
termsToggles[i].addEventListener('click', toggleTerms);
}
}
function toggleTerms() {
var termsSection = document.querySelector('.swatch-label-size');
termsSection.classList.toggle('js-swatch-open');
}
I have three instances on the element with ".swatch-label-size" class in my DOM, but the function only works when I click the first one. Nothing happens on click of the second or third element. Have I not not bound my function to all instances of the class properly?
You are again getting the element inside the listener function toggleTerms so remove that and it works. Just click the text in the snippet below to get the effect of class being toggled. For simplicity, I have toggled the class that change the font color:
function newFunctionTest() {
var termsToggles = document.querySelectorAll('.swatch-label-size');
for (var i = 0; i < termsToggles.length; i++) {
termsToggles[i].addEventListener('click', toggleTerms);
}
}
function toggleTerms() {
this.classList.toggle('js-swatch-open');
}
//initialize listener
newFunctionTest();
.js-swatch-open{
color: red;
}
<h4 class="swatch-label-size swatch__label--error">test1</h4>
<h4 class="swatch-label-size swatch__label--error">test2</h4>
<h4 class="swatch-label-size swatch__label--error">test3</h4>
The termsSection in toggleTerms would always be the first matched element, you may consider to change it into this
function toggleTerms(event) {
var termsSection = event.target;
termsSection.classList.toggle('js-swatch-open');
}
I have created 3 div having the same class in a parent , and on the child element i am adding the active class and on click of second child adding the active class again but this time i want to remove the active state for first element.
How can i remove it in effective way?
Here is my code
<div class="tab-div">
<div class="tab">default</div>
<div class="tab" >hover</div>
<div class="tab">active</div>
</div>
Here is my javascript
var elements = document.querySelectorAll('.tab');
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove('active');
elements[i].onclick = function (event) {
console.log("ONCLICK");
if (event.target.innerHTML === this.innerHTML) {
this.classList.add("active");
}
}
}
You are not removing the active class from all elements when click event is triggered. So, what you can do is to loop over again to all the div and remove the active class on click event. I have created a custom function removeClass() that removes the active class on click event.
var elements = document.querySelectorAll('.tab');
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove('active');
elements[i].onclick = function (event) {
console.log("ONCLICK");
//remove all active class
removeClass();
if (event.target.innerHTML === this.innerHTML) {
this.classList.add("active");
}
}
}
function removeClass(){
for (var i = 0; i < elements.length; i++) {
elements[i].classList.remove('active');
}
}
.active{
color: green;
}
<div class="tab-div">
<div class="tab">default</div>
<div class="tab" >hover</div>
<div class="tab">active</div>
</div>
I suppose it depends how many divs you will ultimately have, and if only one div should be active at a time, but I think it would be more efficient to just find the active div and remove the class from that one rather than looping through all of them e.g.
var oldActiveElement = document.querySelector('.active');
oldActiveElement.classList.remove('active');
var newActiveElement = event.target;
newActiveElement.classList.add('active');
Since all of them have a class called tab, make sure you remove the class or property of active from all the classes by targeting the class tab and it would remove from all without doing any loop. Then add the property to the current one that is clicked.
$(".tab").click(function(){
$(".tab").removeClass('active');
$("this").addClass('active');
});
If the class is in the parent you can do sth like
$(".tab").click(function({
$(".tab").parent().removeClass('active');
$("this").parent().addClass('active');
});
So I have a mini slide menu in my website there is a menu you can choose what you want to read. There are points to click, when u clicked it the point get a red background.
But there is a problem.
When i click one point and then an other point the first clicked point have to lose his background.
Here is my HTML:
<div id="slide_button" onClick="clicked(this);"><dir class="button_1"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_2"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_3"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_4"></dir></div>
<div id="slide_button" onClick="clicked(this);"><dir class="button_5"></dir></div>
Here is my JS:
function clicked(slide_button) {
slide_button.getElementsByTagName("dir")[0].style.backgroundColor="red";
}
HERE IS AN EXAMPLE ON FIDDLE.
My "QUESTION IS" what i have to do to solve that?
What should I pay attention?
First you need to fix your HTML becaue your id values aren't unique. In fact, you don't even need id values, so you should use "slide_button" as a class. You can then use it to select all the buttons:
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
<div onClick="clicked(this);" class="slide_button"><dir></dir></div>
The CSS needs to be changed now so "slide_button" is a class selector, instead of an id selector:
.slide_button {
display: inline-block;
}
As for clearing the background, clear all of them before coloring the selected one red:
function clicked(slide_button) {
var buttons = document.getElementsByClassName('slide_button');
for(var i = 0; i < buttons.length; i++) {
buttons[i].getElementsByTagName('dir')[0].style.backgroundColor = '';
}
slide_button.getElementsByTagName('dir')[0].style.backgroundColor = 'red';
}
jsfiddle
This uses just JavaScript with no JQuery, but if you are using JQuery, you might as well use it here. The code is a lot shorter and easier to follow.
Here's a JQuery version:
$(function() {
$('.slide_button').click(function() {
var $button = $(this);
$button.children(':first').css({ backgroundColor: 'red' });
$button.siblings().children(':first').css({ backgroundColor: '' });
});
});
Note: This registers a click-handler, so you can get rid of the "onclick" attirbutes.
jsfiddle
You have to select all other points and set their background to none.
Or remeber which point is selected and on select another just remove background on last and remeber current point, then set its background to red.
See fiddle: http://fiddle.jshell.net/399Dm/5/
At first id should be unique per element.
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
<div class="slide_button"><dir class="button"></dir></div>
Second, you should store reference of clicked element if you want later remove background color, and instead of inline event handlers or binding all elements would be better if you use event delegation.
Demonstration
(function () {
"use strict";
// getting parent node of divs, due to bind click event. then
var ele = document.querySelector(".slide_button").parentNode,
prev = null; // store previous clicked element
ele.addEventListener("click", clickHandler); // event handler.
function clickHandler(e) {
var t = e.target; // get target of clicked element
// filter by target node name and class. edit: removed class checking
if (t.nodeName.toLowerCase() === "dir") {
// checking value of prev !== null and it's not same element.
if (prev && prev !== t) {
prev.style.backgroundColor = "";
}
prev = t; // store clicked element
t.style.backgroundColor = "red";
}
}
}());
I have fixed the fiddle so that it works hopefully as you plan.
http://jsfiddle.net/399Dm/8/ There you go!
var forEach = function(ctn, callback){
return Array.prototype.forEach.call(ctn, callback);
}
function clear(element, index, array) {
element.getElementsByTagName("dir")[0].style.backgroundColor="";
}
function clicked(slide_button) {
forEach(document.getElementsByClassName("slide_button"), clear);
//.style.backgroundColor="";
slide_button.getElementsByTagName("dir")[0].style.backgroundColor="red";
}
I had a slightly different method than #atlavis but a similar result.
http://fiddle.jshell.net/2AGJQ/
JSFIDDLE DEMO
jQuery
$('.slide_button').click(function(){
$('.slide_button dir').css("background-color", "inherit");
$(this).find('dir').css("background-color", "red");
});
HTML - Your markup is invalid because you have duplicate ids. Make them classes as below instead.
<div class="slide_button" >
<dir class="button_1"></dir>
</div>
<div class="slide_button">
<dir class="button_2"></dir>
</div>
<div class="slide_button">
<dir class="button_3"></dir>
</div>
<div class="slide_button">
<dir class="button_4"></dir>
</div>
<div class="slide_button">
<dir class="button_5"></dir>
</div>
CSS change
.slide_button {
display: inline-block;
}
If you can look at the following jsfiddle, I used jQuery to get what you want.