Reputation: 1092
I have a list view for delete id. I'd like to add a listener to all elements with a particular class and do a confirm alert.
My problem is that this seems to only add the listener to the first element with the class it finds. I tried to use querySelectorAll
but it didn't work.
var deleteLink = document.querySelector('.delete');
deleteLink.addEventListener('click', function(event) {
event.preventDefault();
var choice = confirm("sure u want to delete?");
if (choice) {
return true;
}
});
List:
<?php
while($obj=$result->fetch_object())
{
echo '<li><a class="delete" href="removeTruck.php?tid='.$obj->id.'">'.$obj->id.'</a>'
. '<a href="#" class="delete"></a>
</li>'."\n";
}
/* free result set */
$result->close();
$mysqli->close();
?>
Upvotes: 90
Views: 177865
Reputation: 30
You can do this by adding some methods to the NodeList prototype for doing this. I know this question is old, but this way works really well.
I created a tiny project for this purpose: https://github.com/pejman-hkh/nodelist
In this example, I add all events and the each function to the NodeList prototype.
NodeList = window.NodeList;
NodeList.prototype.each = function (callback) {
this.forEach(function (elm, index) {
callback.call(elm, elm, index);
});
return this;
};
["focusin", "focusout", "load", "beforeunload", "unload", "change", "click", "dblclick", "focus", "blur", "reset", "submit", "resize", "scroll", "mouseover", "mouseout", "mouseup", "mousedown", "mouseenter", "mousemove", "mouseleave", "contextmenu", "wheel", "keydown", "keypress", "keyup", "select"].forEach(function (name, index) {
NodeList.prototype[name] = function (callback) {
this.each(function (elm, index) {
this.addEventListener(name, callback);
});
return this;
}
});
document.querySelectorAll('.delete').click(function (event) {
event.preventDefault();
var choice = confirm("sure u want to " + this.innerHTML + "?");
if (choice) {
return true;
}
})
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<a href="#" class="delete">Delect1</a>
<a href="#" class="delete">Delect2</a>
<a href="#" class="delete">Delect3</a>
</body>
</html>
Upvotes: -1
Reputation: 942
(ES5) I use forEach to iterate on the collection returned by querySelectorAll and it works well :
document.querySelectorAll('your_selector').forEach(item => { /* do the job with item element */ });
Upvotes: 3
Reputation: 1436
A short and sweet solution, using ES6:
document.querySelectorAll('.input')
.forEach(input => input.addEventListener('focus', this.onInputFocus));
Upvotes: 50
Reputation: 193301
You should use querySelectorAll
. It returns NodeList, however querySelector
returns only the first found element:
var deleteLink = document.querySelectorAll('.delete');
Then you would loop:
for (var i = 0; i < deleteLink.length; i++) {
deleteLink[i].addEventListener('click', function(event) {
if (!confirm("sure u want to delete " + this.title)) {
event.preventDefault();
}
});
}
Also you should preventDefault only if confirm === false
.
It's also worth noting that return false/true
is only useful for event handlers bound with onclick = function() {...}
. For addEventListening
you should use event.preventDefault()
.
Demo: http://jsfiddle.net/Rc7jL/3/
ES6 version
You can make it a little cleaner (and safer closure-in-loop wise) by using Array.prototype.forEach iteration instead of for-loop:
var deleteLinks = document.querySelectorAll('.delete');
Array.from(deleteLinks).forEach(link => {
link.addEventListener('click', function(event) {
if (!confirm(`sure u want to delete ${this.title}`)) {
event.preventDefault();
}
});
});
Example above uses Array.from and template strings from ES2015 standard.
Upvotes: 168
Reputation: 1561
The problem with using querySelectorAll
and a for
loop is that it creates a whole new event handler for each element in the array.
Sometimes that is exactly what you want. But if you have many elements, it may be more efficient to create a single event handler and attach it to a container element. You can then use event.target
to refer to the specific element which triggered the event:
document.body.addEventListener("click", function (event) {
if (event.target.classList.contains("delete")) {
var title = event.target.getAttribute("title");
if (!confirm("sure u want to delete " + title)) {
event.preventDefault();
}
}
});
In this example we only create one event handler which is attached to the body
element. Whenever an element inside the body
is clicked, the click
event bubbles up to our event handler.
Upvotes: 70
Reputation: 388436
You have to use querySelectorAll
as you need to select all elements with the said class, again since querySelectorAll
is an array you need to iterate it and add the event handlers
var deleteLinks = document.querySelectorAll('.delete');
for (var i = 0; i < deleteLinks.length; i++) {
deleteLinks[i].addEventListener('click', function (event) {
event.preventDefault();
var choice = confirm("sure u want to delete?");
if (choice) {
return true;
}
});
}
Upvotes: 7