Need to click twice to add/remove a Class with Javascript - javascript

I read some of the answers here similar to my question, but I still don't understand what's going on.
I have this JS snippet:
function renderButtons() {
let buttonCollection = document.getElementsByClassName("btn");
let arrayOfBtn = [...buttonCollection];
arrayOfBtn.forEach(function(element) {
function modifyClass() {
element.classList.toggle("active");
}
element.addEventListener("click", modifyClass);
})
}
That is meant to add/remove the class "active" of a button when I click on it.
This is the HTML:
<div class="panel controls">
<ul>
<li>
<button class="btn btn-pepperonni active">Pepperonni</button>
</li>
<li>
<button class="btn btn-mushrooms active">Mushrooms</button>
</li>
<li>
<button class="btn btn-green-peppers active">Green peppers</button>
</li>
<li>
<button class="btn btn-sauce active">White sauce</button>
</li>
<li>
<button class="btn btn-crust active">Gluten-free crust</button>
</li>
</ul>
</div>
And it works, the problem is that I have to click twice each time on the button to add or remove the class of that button in particular.
Any help will be very appreciated.
Thank you very much!

EDIT:
Remove your RenderButtons function and instead toggle the "active" class once you click the button like this on every ingredient:
document.querySelector('.btn.btn-pepperonni').onclick = function() {
state.pepperonni = !state.pepperonni;
renderEverything()
this.classList.toggle("active");
}
Basically what you do is you call two onclick events on the button and they do not work together.
Also you are over complicating the whole thing with your RenderButtons Functions :)
Hope that helps!

Your JS must be loaded at the end of your HTML. Your HTML will load the content from TOP to BOTTOM. So your Scirpt want to access "btn" elements, which are at the moment not genereted.
First HTML, then JS.
For such a short function, you could use a inline function as below.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div class="panel controls">
<ul>
<li>
<button class="btn btn-pepperonni active">Pepperonni</button>
</li>
<li>
<button class="btn btn-mushrooms active">Mushrooms</button>
</li>
<li>
<button class="btn btn-green-peppers active">Green peppers</button>
</li>
<li>
<button class="btn btn-sauce active">White sauce</button>
</li>
<li>
<button class="btn btn-crust active">Gluten-free crust</button>
</li>
</ul>
</div>
</body>
<script>
var buttonCollection = document.getElementsByClassName("btn");
for (var i = 0; i < buttonCollection.length; i++)
{
buttonCollection[i].addEventListener("click", function(){
this.classList.toggle("active");
});
}
</script>
</html>

As previous answers have shown how to fix your original code I have tried to find a simplified version of what you want to do.
In my solution I am using a "delegated event binding": the click event is bound to the parent <div> element and fires only when the actual click target is of class btn. This approach will work on elements that have not even been created at the time of the binding. And it is more "lightweight", as there is only one binding.
document.querySelector("div.panel.controls")
.addEventListener("click",function(ev){
var cl=ev.target.classList;
if (cl.contains("btn")) cl.toggle("active");
});
.active {background-color: #fcc}
<div class="panel controls">
<ul>
<li>
<button class="btn btn-pepperonni active">Pepperonni</button>
</li>
<li>
<button class="btn btn-mushrooms active">Mushrooms</button>
</li>
<li>
<button class="btn btn-green-peppers active">Green peppers</button>
</li>
<li>
<button class="btn btn-sauce active">White sauce</button>
</li>
<li>
<button class="btn btn-crust active">Gluten-free crust</button>
</li>
</ul>
</div>

Related

finding closest sibling in jQuery

I have the following code in HTML:
$(".remove-post").click((event) => {
$(event.target).fadeOut();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="side-bar">
<button class="remove-post"> delete </button>
<a class="list">
<p>post title</p>
</a>
<button class="remove-post"> delete <button>
<a class="list"><p>another post title</p></a>
</div>
every time that I click on a delete button I want to delete the closest "a" tag with the paragraph inside it as well as the delete button by itself. I was able to delete the button but can't target the closest a tag to that clicked button
I wrote it in jQuery
If the button will always stay before paragraph you can do:
$(".remove-post").on("click", function () {
$(this).next(".list").fadeOut()
$(this).fadeOut()
})
I would recommend you to wrap the paragraph and the button together like:
<div class="side-bar">
<div class="wrapper">
<button class="remove-post">Delete<button>
<a class="list">Another post title</a>
</div>
<div class="wrapper">
<button class="remove-post">Delete <button>
<a class="list">Another post title</a>
</div>
</div>
If you do so, then you can use this:
$(".remove-post").on("click", function () {
$(this).parent().fadeOut()
})
Assuming you want to remove the next a.list sibling, use .next()
$(".remove-post").on("click", function() {
const btn = $(this)
btn.add(btn.next("a.list")).fadeOut()
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="side-bar">
<button class="remove-post">delete</button>
<a class="list"><p>post title</p></a>
<button class="remove-post">delete</button>
<a class="list"><p>another post title</p></a>
</div>
jQuery's .add() is used here to collect both the <button> and <a> so you can fade them out together.

First To-do-list with querySelectorAll [duplicate]

This question already has answers here:
Adding click event listener to elements with the same class
(5 answers)
Closed 4 years ago.
I have some problems with querySelectorAll. Script is working only with querySelector, but it deletes only first li. When I try to replace querySelector with querySelectorAll to make all delete buttons work there is error - "deleteButton.addEventListener is not a function".
html:
body>
<div id="buttons">
<input type="text" placeholder="twoje zadanie...">
<button type="submit" class="add">dodaj</button>
</div>
<div id="tasks">
<ul>
<li><button class="done">done</button>
asd
<button class="delete">x</button></li>
<li>
<button class="done">done</button>
asdd
<button class="delete">x</button></li>
<li>
<button class="done">done</button>
dsad
<button class="delete">x</button></li>
</ul>
</div>
<script src="script.js"></script>
</body>
js:
var deleteButton = document.querySelectorAll('.delete');
deleteButton.addEventListener('click', function() {
var li = document.querySelector('li');
li.classList.add('li-delete');
});
Reason: Coz querySelectorAll get you the list of matching nodes. And there is no .addEve.. property that you can use on list.
Moreover, document.querySelector('.delete'); will get you the first button and will only add listener to the this button but you don't want.
If you want to add listeners to all of the elements you should loop through the list and add a listener on all of the matched elements. Like
var el = document.querySelectorAll('.delete');
for(var i=0; i<el.length; i++){
el[i].addEventListener('click', function(){
console.log("clicked");
var li = this.parentNode;
li.classList.add('li-delete');
})
}
.li-delete{
color : red;
}
<div id="tasks">
<ul>
<li><button class="done">done</button>
asd
<button class="delete">x</button></li>
<li>
<button class="done">done</button>
asdd
<button class="delete">x</button></li>
<li>
<button class="done">done</button>
dsad
<button class="delete">x</button></li>
</ul>
</div>
addEventListener on NodeList
You have to iterate through each node and attach the event listener if you want to use .querySelectorAll to select your elements.
It looks like you might be new to working with the DOM in JavaScript. If that's the case, I'd recommend taking a look at jQuery. It's not a lightweight library, but it makes many of these things much easier.
2 Problens in your code.
First querySelectorAll will return an array of all the elements that match the query. I added a console.log(deleteButtons), so you can see what thequerySelectorAll`` is generating. You will need a loop to add the event listener to each of the elements in the array.
Second, you can use this to get the button that trigger the event and then go get their parent <li> using the js .parentNode
Hope this helps :)
var deleteButton = document.querySelectorAll('.delete');
console.log(deleteButton);
for(let i=0; i<deleteButton.length;i++){
deleteButton[i].addEventListener('click', function() {
var li = this.parentNode;
li.classList.add('li-delete');
})
};
.li-delete {display:none;}
<div id="buttons">
<input type="text" placeholder="twoje zadanie...">
<button type="submit" class="add">dodaj</button>
</div>
<div id="tasks">
<ul>
<li><button class="done">done</button>
asd
<button class="delete">x</button></li>
<li>
<button class="done">done</button>
asdd
<button class="delete">x</button></li>
<li>
<button class="done">done</button>
dsad
<button class="delete">x</button></li>
</ul>
</div>
<script src="script.js"></script>

buttons to activate buttons that toggle from one div to another

Apologies in advance if this is a simple trick, but I'm not any good at javascript so I don't know how to do it...
I have two buttons (blue and yellow) that toggle between two divs with content. On another part of the page, I have another two buttons (also blue and yellow) that are supposed to activate the same-colored button of these two toggle buttons. So blue will activate toggle-blue and yellow will activate toggle-yellow. I used the below script I found on here for the toggle feature:
<div class="flr-wrap">
<ul>
<li><a class="button active" data-rel="#content-a" href="#">a button</a>
</li>
<li><a class="button" data-rel="#content-b" href="#">b button</a>
</li>
</ul>
<div class="flr-inner">
<div class="container" id="content-a">AAA</div>
<div class="container" id="content-b">BBB</div>
</div>
</div>
// set content on click
$('.button').click(function (e) {
e.preventDefault();
setContent($(this));
});
// set content on load
$('.button.active').length && setContent($('.button.active'));
function setContent($el) {
$('.button').removeClass('active');
$('.container').hide();
$el.addClass('active');
$($el.data('rel')).show();
}
from here:
jsfiddle
What do I add to make the other two buttons trigger the active states of their corresponding toggle buttons?
Many thanks in advance for any help!
Since you said you need the second set of buttons to trigger actions of the first set, this means that buttons do the same thing.
Here's an example of how this works:
http://jsfiddle.net/ivanbatic/b43m405x/
Javascript:
$('.activator').on('click', function () {
var target = $(this).attr('data-target');
$('.panel').removeClass('active');
$(target).toggleClass('active');
});
HTML
<section>
<button class="activator" data-target=".panel-a">Blue</button>
<button class="activator" data-target=".panel-b">Yellow</button>
<section>
<div class="panel active panel-a">First Panel</div>
<div class="panel panel-b">Second Panel</div>
</section>
<section>
<button class="activator" data-target=".panel-a">Blue</button>
<button class="activator" data-target=".panel-b">Yellow</button>
</section>
Also, you are not using buttons in your example, you are using links. Links are meant to take you to another page, buttons are meant to trigger an action.
If you want buttons to look like plain text, use CSS for styling.
You can do pretty much the same, just use the selector based on your data-rel to add the active class and add the active class to the button's data-rel statement, like that it's quite easy to always toggle the matching tags
function setContent($el) {
var rel = $el.data('rel');
$('.active').removeClass('active');
$('.container').hide();
$('[data-rel="' + rel + '"]').addClass('active');
$(rel).show();
}
$(function() {
// the right place to fire the initial setContent (all scripts are ready and page is loaded)
setContent($('.button.active'));
// add event handlers in ready event (DOM is most surely there)
$('.button').click(function(e) {
e.preventDefault();
setContent($(this));
});
});
.container {
display: none;
}
.button.active {
color: #C00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="flr-wrap">
<ul>
<li><a class="button active" data-rel="#content-a" href="#">a button</a>
</li>
<li><a class="button" data-rel="#content-b" href="#">b button</a>
</li>
</ul>
<div class="flr-inner">
<div class="container" id="content-a">
AAA
</div>
<div class="container" id="content-b">
BBB
</div>
</div>
<ul>
<li><a class="button active" data-rel="#content-a" href="#">a button</a>
</li>
<li><a class="button" data-rel="#content-b" href="#">b button</a>
</li>
</ul>
</div>

Changing class to active using JavaScript onClick

I've tried my best to figure this out myself but to no avail as I'm new to web development. It's probably really basic but I'd really appreciate some help because I'm going around in circles here..
I have a Google map search form (essentially a store locator) and what I've done for the search results is split into two tabs; a list and a map.
What I would like to do is have the map tab always be the active tab when the submit button is pressed in the search form.
This is the HTML code:
<ul class="nav nav-tabs" id="myTab">
<li id="maptab" class="active">Map</li>
<li id="listtab" >List</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="resmap">
<div id="map_canvas"></div>
</div>
<div class="tab-pane" id="reslist">
<div id="results">
<ul class="res-list" id="list"></ul>
</div>
</div>
</div>
So basically for the map items I'm trying to get the code to return to
div class="tab-pane active"
and
li class="active"
Presumably I have to add an onclick element to the submit button??
The html for the submit button in the form is
<input type="submit" name="op" id="edit-submit" value="Search" class="btn btn-primary" />
In your case, I presume you are trying to add the "active" class to that li element:
var button = document.getElementById('edit-submit');
button.onclick= function() {
// this adds the 'active' class to the classes that the element already has
var maptab = document.getElementById('maptab');
maptab.className = maptab.className + ' active';
};

How to select child div within parent div

I want to select html of class "postHandel" when I click replyBtn.
There are multiple "repost" divs, I want postHandel of the current div in which I am clicking replyBtn.
<div class="repost" data-id="52">
<div class="profileImg"></div>
<div class="postWrap">
<div class="postUser">Tejas Kulkarni</div>
<div class="postHandel">#tejas</div>
<div class="postText"> </div>
</div>
<i class="icon-chevron-down"></i>
<div class="clearfix"></div>
<div class="postOptions twtOptRP52">
<ul>
<li> <a class="btn btn-mini rtBtn" data-id="96"><i class="icon-retweet"></i> Repost</a></li>
<li> <a class="btn btn-mini replyBtn" data-id="96"><i class="icon-reply"></i> Reply</a></li>
<li> <a class="btn btn-mini favBtn" data-id="96"><i class="icon-star"></i> Fav</a></li>
<li><div class="loadingPostsBtn hideme loadingBtn-96 hideme"><img src="http://linkzone.dev/assets/img/ajax-loader.gif"></div></li>
<li><div class="loadingFailBtn hideme loadingFail-96 hideme"><img src="http://linkzone.dev/assets/img/ajax-fail.gif"></div></li>
</ul>
</div>
My jQuery Code is :
$(document).on("click",".replyBtn",function(){
var postHandel = $(this).closest(".postWrap").html('');
var log = $(postHandel).closest(".postHandel").html();
console.log(log);
});
Try this:
var log = $(this).closest(".repost").find(".postHandel:first").html();
$(this) // current element (.replybtn)
.closest('.report') // up to main wrapper (top-most grouping element)
.find('.postWrap > .postHandel') // down to postHandel
.html(); // the end value
You may not even need the .postWrap > discriminator, but it does make sure that it's the that .postHandel you're after.

Categories

Resources