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>
Related
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.
I want to transverse upwards in javascript. like if i give input an element it will show all its parent elements till html tag but its not working like that. It only shows DIV,BODY,HTML.
function Transverse(p) {
var path = "";
var A = [];
var element = document.querySelector(document.getElementById(p).nodeName);
path = element.parentElement;
while (path) {
A.push(path);
path = path.parentElement;
}
console.log(A);
}
<div>
<button id="btn1" onclick="Transverse('btn1')">button 1</button>
<ul>
<button id="btn2" onclick="Transverse('btn2')">button 2</button>
<li>
<button id="btn3" onclick="Transverse('btn3')">button 3</button>
</li><br>
<section>
<a href="#">
<button id="btn4" onclick="Transverse('btn4')">button 4</button>
</a>
</section>
</ul>
<ol>
<li>
<h1>End of Page</h1>
<button id="btn5" onclick="Transverse('btn5')">Button 5</button>
</li>
</ol>
</div>
Thanks all it is working now ! I did the following Changes
function Transverse(p){
var A=[];
var element = document.getElementById(p);
var path=element.parentElement;
while(path){
A.push(path.nodeName);
path=path.parentElement;
}
console.log(A);
}
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>
My template involving parent div with attribute of data-template and child button with attribute of data-click:
<script type="text/html" id="containerTemplate">
<div data-template="myTemplate">
<ul>
<li>
<button type="button" data-click="done">
<span>some text</span>
</button>
</li>
</ul>
</div>
</script>
How can i select the button with the data-click="done"?
I've tried this
const doneBtn = document.querySelector('[data-template = myTemplate] [data-click = done]');
if (doneBtn) {
//register some event listeners
}
But the doneBtn is returning null.
You put your html code in javascript tags that's why javascript was unable to access your html DOM. Try below code it will work.
<div data-template="myTemplate">
<ul>
<li>
<button type="button" data-click="done">
<span>some text</span>
</button>
</li>
</ul>
</div>
<script type="text/javascript">
const doneBtn = document.querySelector('[data-template = myTemplate] [data-click = done]');
if (doneBtn) {
//register some event listeners
console.log($(doneBtn).html());
}
</script>
I'm trying to create a To Do list, and when the user enters a new task, and clicks the button, the javascript should create a li element containing a span that holds the user's entry, then add that li element to the ol in my HTML.
My HTML looks like this:
<body>
<h1>To Do:</h1>
<section>
<input type="text" id="add_todo">
<span id="add_task_error"> </span>
<input type="button" id="add_task" value="Add task">
<div id="empty_message" class="open">
<h3>You have no tasks left to accomplish!</h3>
</div>
<div id="tasklist">
<ol class="list">
</ol>
</div>
</section>
</body>
This is the function that is not working:
var newSpan = $('<span>input</span>').addClass("task");
//wrap it in a <li> element
newSpan = (".task").wrap("<li></li>");
$(".list").append(newSpan);
I also tried it this way:
var new_task = $('<li>*</li>').addClass('task');
new_task.appendTo('ol.list');
new_task.setAttribute('id', 'new_task');
$("#new_task").text(input);
Both ways did not work- when I clicked the Add Task button (which is not the problem- I tested it), nothing happened on the screen...
What am I doing wrong???
Try this
$(document).ready(function(){
$('#add_task').click(function(){
var task = $('#add_todo').val();
var html = '<li><span>'+task+'</span></li>';
$('.list').append(html);
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>To Do:</h1>
<section>
<input type="text" id="add_todo">
<span id="add_task_error"> </span>
<input type="button" id="add_task" value="Add task">
<div id="empty_message" class="open">
<h3>You have no tasks left to accomplish!</h3>
</div>
<div id="tasklist">
<ol class="list">
</ol>
</div>
</section>
Create the element, set all the attributes and when, you are done, add it to the ol.
var new_task = $('<li></li>').addClass('task');
new_task.text($("#add_todo").val()); //this is the value of the input
new_task.attr('id', 'new_task'); //use attr instead of setAttribute
new_task.appendTo('ol.list');
FIDDLE
Hope this works for you
JS code:
$("#add_task").click(function(){
var value = $("#add_todo").val();
$(".list").append("<li class='task'><span>"+ value +"</span></li>")
});
Here is the working Plnkr
This should be your code.
Call addLI() on click of your button
<input type="button" id="add_task" value="Add task" onclick="addLI()">
function addLI() {
//check for empty value
if ($('#add_todo').val() == "") {
alert("Please Add Todo.");
return;
}
//generate html for li
var html = "<li class='task' id='new_task'><span>" + $('#add_todo').val() + "</li>";
//append li to order list
$(".list").append(html);
}
Also try to hide the div on which you are showing the message before adding any new task.
<div id="empty_message" class="open">
<h3>You have no tasks left to accomplish!</h3>
</div>
$('.open').hide(); on click event of add task