Add querySelectorAll to add a class to a button - javascript

I'm having difficulty with using Javascript to add a class to a button.
Context: I have multiple cards in an instragram type format with a post and a "like" button. I want to add a class of card__like-button which changes the image to a filled heart but i remembered that querySelector only applies to the first element, instead i tried using querySelectorAll but now the code doesn't apply to anything.
First attemp:
// Controls for active like button
let likeButton = document.querySelector(".card__like-button");
// Event listener for like button click
likeButton.addEventListener("click", likeButtonClick);
// Add class on button click
function likeButtonClick() {
likeButton.classList.toggle("card__like-button_active");
}
Second attemp
// Controls for active like button
let likeButton = document.querySelectorAll(".card__like-button");
// Event listener for like button click
likeButton.addEventListener("click", likeButtonClick);
// Add class on button click
function likeButtonClick() {
likeButton.classList.toggle("card__like-button_active");
}
I created the following codepen to replicate the problem.
I've search on the site, w3schools documentation, etc. and can't seem to find what am I doing wrong.

Because of the document.querySelectorAll method will return an array of NodeList details see here, you cannot directly assign the addEventListener event to a list.
Instead, you have to loop through each element and assign events to it
document.querySelectorAll(".card__like-button").forEach(ele => {
ele.addEventListener("click", likeButtonClick);
});
// Add class on button click
function likeButtonClick() {
this.classList.toggle("card__like-button_active");
}

Try it :
let likeButtons = document.querySelectorAll(".card__like-button");
Array.from(likeButtons).forEach(ele => {
ele.addEventListener("click", likeButtonClick);
});
// Add class on button click
function likeButtonClick() {
this.classList.toggle("card__like-button_active");
}

Related

JQuery - Function applying only for first element with class

I'm trying to update a modal & video attributes on button click.
It works well but the problem is that it only apply this when i click on the first button ( first element with the class videoBtn ), i want it to be applied on all other buttons with the same class
here is my code
$(".videoBtn").click(function(){
$("#video").attr('src',$(".videoBtn").data('src'));
$(".modal").attr('id', $(".videoBtn").data('target').substring(1));
});
You are not using value of currently clicked element, but first with class, you should use $this instead of $('.videoBtn')
$(".videoBtn").click(function(){
$("#video").attr('src',$(this).data('src'));
$(".modal").attr('id', $(this).data('target').substring(1));
});
$(".videoBtn").each(function(){
$(this).on('click', function() {
$("#video").attr('src',$(".videoBtn").data('src'));
$(".modal").attr('id', $(".videoBtn").data('target').substring(1));
})
})

OffcanvasMenu plugin - click event, Shopware 6

I have a problem with adding a click event for list of OffcanvasMenu. I need add this event for every li element. I'm working with Shopware 6.
But when I'm trying to add click event for li element with jQuery, nothing happens.
I've extended OffcanvasMenu. Here is my code:
import OffcanvasMenuPlugin from 'src/plugin/main-menu/offcanvas-menu.plugin.js';
export default class ExtendOffcanvasMenuPlugin extends OffcanvasMenuPlugin {
init() {
super.init();
this._registerEvents();
console.log("inner");
}
_registerEvents() {
super._registerEvents();
let list = document.querySelector('.navigation-offcanvas-list-item');
console.log(list);
list.addEventListener('click', (e) => {
console.log("inner event");
e.preventDefault();
});
}
}
In main.js file I overriding this plugin:
PluginManager.override('OffcanvasMenu', ExtendOffcanvasMenuPlugin, '[data-offcanvas-menu]');
It's any possibility to add event on every li element in OffcanvasMenu plugin?
the general problem seems to be that the current code is using querySelector to collect all elements. However querySelector does only yield the first element which matches the selector, even if there are multiple ones, see: https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector
You can solve this by using querySelectorAll which does essentially the same but returns an iterable list of all found elements. Then you can iterate over the list and attach the listener to each element:
import OffcanvasMenuPlugin from 'src/plugin/main-menu/offcanvas-menu.plugin.js';
export default class ExtendOffcanvasMenuPlugin extends OffcanvasMenuPlugin {
_registerEvents() {
super._registerEvents();
let list = document.querySelectorAll('.navigation-offcanvas-list-item');
console.log(list);
list.forEach((listItem) => {
listItem.addEventListener('click', (e) => {
console.log("inner event");
e.preventDefault();
});
});
}
}
This would work in theory but in practice the a.navigation-offcanvas-link is inside the <li> where you want to attach the listener. The a.navigation-offcanvas-link element has already an event listener (_getLinkEventHandler) and also takes up all the space inside the <li> which is why the <li> itself is not actually clickable.
A workaround could be to make remove the listener first from a.navigation-offcanvas-link and make it non-clickable but it depends on what you want to achieve. Should something additional be executed everytime a menu item is being clicked? Then you could consider extending method _getLinkEventHandler directly even though it is marked as private and might change in future versions.

Classes on tab key press not being added and removed correctly

I am trying to add a CSS class to all objects that have been tab-key navigated to.
I have the following code, it's running a function on keydown checking if the tab key has been pressed. And tries to remove the tabbed CSS class if it already exists. But only one element on my page (top element) removes the CSS for all other elements. Instead of the class being removed if it exists when someone tab navigates there.
I use this code snipped in a Gatsby site
function checkTabPress(e) {
if (e.keyCode === 9) {
if(e.target.classList.contains('tabbed')) {
e.target.classList.remove('tabbed')
}else {
e.target.classList.add('tabbed');
}
}
}
document.addEventListener('keydown', checkTabPress);
Instead of adding event listener on the document, you should add one for each element you want to have this functionality (you should have ids for the elements). Otherwise the event listener will be called each time you tab, even if you do not tab the elements you want, will check the whole document as it is now doing it.
Maybe you can do something like this.
function checkTabPress(e) {
if (e.keyCode === 9) {
if(e.target.classList.contains('tabbed')) {
e.target.classList.remove('tabbed')
}else {
e.target.classList.add('tabbed');
}
}
}
var myElement = document.getElementById("my_cool_id");
myElement.addEventListener('keydown', checkTabPress);
//element
<div id="my_cool_id"/>
Another option, which i forgot about is this. You can loop through the elements including the class tabbed. However, this will work if all elements by default have this class.
document.querySelectorAll('.tabbed').forEach(item => {
item.addEventListener('keydown', checkTabPress)
})
Or you can just create a new class, for example called tabbable, which you will put on every element you want to have this event listener.
document.querySelectorAll('.tabbable').forEach(item => {
item.addEventListener('keydown', checkTabPress)
})

change div class onclick on another div, and change back on body click

Let me define the problem a little bit more:
i have
<div class="contact">
<div id="form"></div>
<div id="icon"></div>
</div>
i want onclick on #icon, to change the class of .contact to .contactexpand( or just append it).
Then i want that the on body click to change the class back, but of course that shouldnt happen when clicking on the new class .contactexpand, and if possible that clicking on icon again changes the class back again.
I tried numerous examples and combinations but just couldn't get the right result and behavior.
Check this: Working example
Let's go step by step
I want onclick on #icon, to change the class of .contact to .contactexpand( or just append it). […] and if possible that clicking on icon again changes the class back again.
You want to use the toggleClass() method to achieve this. Simply:
$('#icon').on('click', function(e){
$(this).parent()
.toggleClass('contact')
.toggleClass('contactexpand');
});
Then i want that the on body click to change the class back
You will have to make sure that body removes contactexpand class and adds contact. At this point I would just give the container element an id (or class if you prefer), just to make things simpler. Then what you do is pretty simple:
$('body').on('click', function(e){
$('#thisdiv')
.removeClass('contactexpand')
.addClass('contact');
});
but of course that shouldnt happen when clicking on the new class .contactexpand.
This is the step that the other answers missed, I think. Since everywhere you click, you also click on the body element, you will always trigger the click event on the body, hence removing the contactexpand class and adding the contact one.
Enter event.stopPropagation(). This method will make sure that the events doesn't bubble up the DOM, and will not trigger the body click.
$('#thisdiv').on('click', function(e){
e.stopPropagation();
});
Working example
You can add a class to parent element like the following code.
$(".contact #icon").click(function(){
var element = $(this).parent(".contact");
element.removeClass("contact").addClass("contactexpand");
});
I like to the jQuerys toggleClass function like so:
$('#icon').click(function(){
$('#contactbox').toggleClass('contact');
$('#contactbox').toggleClass('contactexpand');
});
Or you could use addClass('className') and removerClass('className') if you would like to apend it rather than toggle it :)
Here is an example: http://jsfiddle.net/aUUkL/
You can also add an onclick event to the body of the page and use hasClass('className') to see whether or not to toggle the class when the body is clicked. You could use something like this (Although I havent tested this bit!):
$('body').click(function(){
if( $('#contactbox').hasClass('contactexpand') ){
$('#contactbox').addClass('contact');
$('#contactbox').removeClass('contactexpand');
}
});
You can do this
$('body').on('click', function(event) {
if ($(event.target).attr('id') == 'icon') {
$(event.target).parent().toggleClass('contactexpand');
} else {
$('.contact').removeClass('contactexpand');
}
});
Check out this jsfiddle
var $contact = $('.contact');
$contact.find('#icon').click(function(e, hide) {
e.stopPropagation();
$contact[hide ? 'removeClass' : 'toggleClass']('contactexpand');
});
$(document).on('click', function(e) {
if (e.srcElement === $contact[0]) return;
$contact.find('#icon').trigger('click', true);
});
http://jsfiddle.net/kZkuH/2/

A way to check if any element of class is clicked

Is there a way to check if any of the elements of a class have been clicked with jQuery? I want to detect if an element with a certain class has been clicked.
I want to detect if an element with a certain class has been clicked.
Well you could always subscribe to the .click() event handler which will be invoked when a DOM element is being clicked upon:
$('.someClass').click(function() {
// here you could use "this" to get the DOM element that was clicked.
});
you could then associate some metadata information with this DOM element if you want to track it using the .data() function:
$('.someClass').click(function() {
var isClicked = $(this).data('clicked');
if (!isClicked) {
// it's the first time we are clicking on this element
$(this).data('clicked', true);
} else {
// the user has already clicked on this element
}
});

Categories

Resources