Javascript Toggle class on elements with class - javascript

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");
});

Related

Toggle add and remove class in JavaScript with if condition

I have a element with an id="caretToggle" and a button with onclick="caretToggle()". This fires a function that adds a class to invert the caret on the button.
I am successful in running:
function caretToggle() {
var caretElement = document.getElementById("caretToggle");
caretElement.classList.add("dropup");
}
But This leaves the caret inverted after the collapse is closed. I want to toggle the caret once the button is clicked again.
This is my condition code that I have failed to get working:
function caretToggle() {
var caretElement = document.getElementById("caretToggle");
if (caretElement.classList.contains("dropup")) {
caretElement.classList.remove("dropup");
} else {
caretElement.classList.add("dropup");
}
}
Thank you in advance for any help you may provide!
You dont need to check wheter contains or not.
What you can do simply use toggle function on classList :)
function caretToggle() {
var caretElement = document.getElementById("caretToggle");
caretElement.classList.toggle("dropup");
}
And also there is a conditional toggle like:
caretElement.classList.toggle("dropup", counter < 10)
Check here from MDN
If you want to toggle class simply do it like this
let caretElement = document.getElementById("caretToggle");
function caretToggle() {
caretElement.classList.toggle("dropup");
console.log('class attribute contains: ', caretElement.className)
}
span {
margin:10px;
}
.dropup {
background-color: purple;
padding: 1em;
border-radius: 10px;
color: white;
}
<span id="caretToggle">HTMLElement</span>
<br/>
<br/>
<br/>
<br/>
<button onclick="caretToggle()">Click</button>

Most efficient way to have multiple toggle items on a page

If I've got multiple items that I want to change from a display of 'none', to a display of 'block', what's the most efficient way of doing it?
The JS I would use for a single item is below, but I imagine there are several on a page or site. Should I make use of function constructors somehow?
var sideNav = document.getElementById('sideNav');
var menuButton = document.getElementById('menuButton');
function toggle() {
if(sideNav.style.display) {
sideNav.style.display = '';
} else {
sideNav.style.display = 'block';
}
}
menuButton.addEventListener('click', toggle);
Take a look, see if this helps you.
I did it with vanilla JS, I don't know if you are currently using jQuery (would be easier if yes)
What I did:
Every button have it's own id that is used to "connect" to the elements that it should toggle.
First I add the listener to all buttons, passing it's id when the function is called.
Then in the function, I used document.querySelectorAll to get all elements with the class that should be hidden/show.
Then finally I run a loop in those elements, showing or not showing, depending on it's current 'display'.
var menuButtons = document.querySelectorAll('.menuButton');
menuButtons.forEach(function(btn){
btn.addEventListener("click", toggle.bind(this, btn.id));
})
function toggle(id) {
var sideNav = document.querySelectorAll('.nav_' + id);
sideNav.forEach(function(el){
if (el.style.display == 'none'){
el.style.display = "block";
} else {
el.style.display = "none"
}
})
}
div{
height: 30px;
width: 50px;
margin: 2px 0;
background: #999;
text-align: center
}
<button id="menuButton1" class="menuButton">Toggle 1</button>
<button id="menuButton2" class="menuButton">Toggle 2</button>
<button id="menuButton3" class="menuButton">Toggle 3</button>
<div class="nav_menuButton1">1</div>
<div class="nav_menuButton1">1</div>
<div class="nav_menuButton2">2</div>
<div class="nav_menuButton3">3</div>
<div class="nav_menuButton3">3</div>
<div class="nav_menuButton3">3</div>
Probably there are better approaches, but I'm now in a hurry and this is the best I could think in that moment
Use JQuery to obtain it:
$(document).ready(function(){
$('#menuButton').click(toggle);
});
function toggle(){
$('.toggle-item').each(function(){
$(this).show();
})
}
and for all you items, add the toggle-item class with this css:
.toggle-item{
display: none;
}
If for every button there is an item to show, this is the way:
$(document).ready(function(){
$('.menuButton').each(function(){
var button = $(this);
button.click(function(){
toggle(button.attr('data-target')));
});
});
});
function toggle(itemId){
$(itemId).show();
}
Adding this attribute to button:
<button class="menuButton" data-target="#toggle-item-1"></button>

Remove class from one element, while adding that class to another element using javascript

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");
}

Toggles class function only works on first element

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');
}

JS Classlist remove

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)

Categories