onclick of a button with a class of obliterate, I want to have my following code take a bunch of identical buttons, besides its unique id and then delete it. The Buttons can be through innerHTML at any time from user input. I want to remove the button onclick, after a confirm This is my current code:
document.getElementsByClassName('obliterate').onclick = function() {
if (confirm('Are you sure you want to delete this?')){
//get this then remove it with remove(this.id);
}
}
Should be straight forward, attach event handler to elements, remove element
var elems = document.querySelectorAll('.obliterate');
for (var i=0; i<elems.length; i++) {
elems[i].addEventListener('click', function() {
if ( confirm('Are you sure you want to delete this?') ) {
this.parentNode.removeChild(this);
}
}, false);
}
If the elements don't exist on pageload, you have to delegate, and doing that without library can be somewhat complicated, depending on what selector you want to match, if there are children inside the clicked element etc. but here's a simlified version
document.addEventListener('click', function(event) {
var clicked = event.target;
var elems = [].slice.call(document.querySelectorAll('.obliterate'));
if ( elems.indexOf(clicked) !== -1 ) {
if ( confirm('Are you sure you want to delete this?') ) {
clicked.parentNode.removeChild(clicked);
}
}
}, false);
FIDDLE
You can use the bind function to provide context so in your case:
element.onclick = function(){ ... }.bind(this);
Related
I have element which has two event listeners that are triggered depending of his class name. During click event, his className is changing, and this another class has its own different event listener. Two events should be triggered alternately by every click.
During first click listener calls function editClub, but all the next clicks calls two functions. I don't know why that removed-class-event is triggered. Maybe its because after each event function callListeners is executed, and there are multiple listeners on one object? But should be triggered just one. Later I wrote removeListeners function which remove all existing listeners and put her to call just before callListeners function. But then just editClub function is executed by every click. What's wrong with my code?
function callListeners()
{
if ( document.getElementsByClassName('editBtn') )
{
let x = document.getElementsByClassName('editBtn');
for ( let i = 0; i < x.length; i++ )
{
x[i].addEventListener('click', editClub);
}
}
if ( document.getElementsByClassName('saveBtn') )
{
let x = document.getElementsByClassName('saveBtn');
for ( let i = 0; i < x.length; i++ )
{
x[i].addEventListener('click', saveClub);
}
}
}
function editClub(event)
{
event.preventDefault();
this.setAttribute('src','img/\icon_save.png');
this.setAttribute('class','saveBtn');
//removeListeners(); <-- here I placed removeListeners function
callListeners();
}
function saveClub(event)
{
event.preventDefault();
this.setAttribute('src', 'img/\icon_edit.png');
this.setAttribute('class', 'editBtn');
//removeListeners(); <-- here I placed removeListeners function
callListeners();
}
It looks like you are not removing the classes when the click event happens so after the first click the element has both classes.
Just changing an element's class does not change the event listeners that were setup on it previously. They will still be there unless you explicitly remove them, or the elements themselves are destroyed. And you get multiple calls because you keep adding new listeners without removing the old ones.
You could on each click remove the old listener and add the new listener
function editClub(){
this.removeEventListener("click",editClub);
this.addEventListener("click",saveClub);
}
function saveClub(){
this.removeEventListener("click",saveClub);
this.addEventListener("click",editClub);
}
But that is a bit tedious. Instead you can setup a delegated event listener on a static parent like document. Doing so allows for a single event listener which will be called when either button is clicked. Then in that listener you can check the element's class, and execute the appropriate function for it:
function clubAction(event){
//get a reference to the element clicked
var element = event.target;
//call the appropriate function
//or just do the work here
if(element.classList.contains("editClub")){
editClub.call(element,event);
} else if(element.classList.contains("saveClub")) {
saveClub.call(element,event);
}
}
document.addEventListener("click",clubAction);
classList is a property that lets you get,set,remove, and other operations for the classes of the element.
Demo
function clubAction(event) {
var element = event.target;
if (element.classList.contains("editClub")) {
editClub.call(element,event);
} else if (element.classList.contains("saveClub")) {
saveClub.call(element,event);
}
}
document.addEventListener("click", clubAction);
function editClub(event) {
event.preventDefault();
this.classList.remove('editClub');
this.classList.add('saveClub');
this.innerText = "Save";
}
function saveClub(event) {
event.preventDefault();
this.classList.add('editClub');
this.classList.remove('saveClub');
this.innerText = "Edit";
}
.saveClub {
background:#0F0;
}
.editClub {
background:#FF0;
}
<button class="saveClub">Save</button>
<button class="editClub">Edit</button>
I have a eventlistener looking for a click on DOM elements with a certain class, and then changing innerHTML. It works, except it changes the innerHTML on all elements with the same class, and not just the one clicked. Is there a way to limit the scope to the element that was clicked, or do I need to give all the elements their own ID and call them based on IDs?
This is the function that I'm using:
$("button.accordion").click(function(){
if ($(".caretUD").html("▼")) {
$(".caretUD").html("▲");
} else {
console.log("I'm not working...");
}
});
Is that helps ?
this is the current clicked element.
Notice that the event.currentTarget is the element where the event is recorded and this the element who fire the event (can be a child of the event.currentTarget or itself). In your case, with a button, it should be the same.
$("button.accordion").click(function(event) {
if ($(this).html("▼")) {
$(this).html("▲");
} else {
console.log("I'm not working...");
}
});
If .caretUD and button.accordian are both contained with the same container element, what you want is:
$("button.accordion").click(function() {
var caret = $(this).closest(".container").find(".caretUD");
if (caret.html() == "▼") {
caret.html("▲");
} else {
console.log("I'm not working");
}
});
Replace .container with the actual class of the element that contains the button and the corresponding caret.
var els = document.getElementsByClassName("button.accordion"); // get all the elements with a certain class
for (var i = 0; i < els.length; i++){
els[i].addEventListener('click',function(e){
e.target.innerHTML = "something"; // e attribute is the key in this solution, as it gets the single DOM element that fired the event
});
}
jQuery solution:
$("button.accordion").click(function(){
if ($(this).html() == "▼") {
$(this).html("▲");
} else {
console.log("I'm not working...");
}
});
I am having some difficulty using parentNode.removeChild(). I have a list of 'items' in an un-ordered list, each have there own delete button. I am trying bind a click event to each individual button that will delete it's respective parent 'item'.
My code so far:
<ul class="list">
<h2>This is a list</h2>
<li class="item">
<h3>Some Item</h3>
<button class="delete">Delete</div>
</li>
<li class="item">
<h3>Some Item</h3>
<button class="delete">Delete</div>
</li>
<li class="item">
<h3>Some Item</h3>
<button class="delete">Delete</div>
</li>
</ul>
var childElements = document.getElementsByClassName('item');
var buttonElement = document.getElementsByClassName('delete');
function deleteItem(buttonsClass, childClass) {
for (var i=0;i<buttonsClass.length;i++) {
var child = childClass[i];
buttonsClass[i].addEventListener('click', function(child) {
childClass[i].parentNode.removeChild(childClass[i]);
}, false);
}
}
deleteItem(buttonElement, childElements);
I know there is an easier way to do this with jQuery but i really want to solve this with plain javascript. Thank you for any and all help.
This is a perfect case for event delegation. No need for jQuery at all:
(function(window, htmlElement) {
'use strict';
htmlElement.addEventListener("click", handleClick, false);
function handleClick(event) {
if (event.target.classList.contains("delete")) {
event.preventDefault();
removeItem(event.target);
}
}
function removeItem(button) {
var item = getItem(button),
confirmMessage;
if (item) {
confirmMessage = item.getAttribute("data-confirm");
if (!confirmMessage || window.confirm(confirmMessage)) {
item.parentNode.removeChild(item);
}
}
else {
throw new Error("No item found");
}
}
function getItem(button) {
var element = button.parentNode,
item = null;
while (element) {
if (element.nodeName === "LI" || element.nodeName === "TR") {
item = element;
break;
}
element = element.parentNode;
}
return item;
}
})(this, this.document.documentElement);
You have one click handler for the entire page, regardless of how many delete buttons you have. This should also work for list items or table rows, and by specifying a data-confirm attribute on your buttons, it will pop up a confirm box before removing it.
<button type="button" class="delete"
data-confirm="Are you sure you want to delete this item?">
Delete
</button>
You can also easily change this so it uses another attribute to find the delete button:
<button type="button" class="delete"
data-delete
data-confirm="...">
Delete
</button>
Just change the condition of the if statement in the handleClick function to:
if (event.target.hasAttribute("data-delete")) {
event.preventDefault();
removeItem(event.target);
}
This decouples your behavior from styling. You can use the delete class name for styling, and the data-delete attribute for JavaScript behavior. If you need to change the name of the CSS delete class for any reason, or use a different class, because you decide to use a third party CSS framework like Bootstrap, then you don't need to change a single line of JavaScript.
The last advantage here is that the click handler is attached to the document.documentElement object, which is available the moment JavaScript begins executing and represents the <html> element. No need for jQuery's document ready event handler. Just attach the click handler and import the script at any point on the page.
The problem is that your childClass[i] that you call when you click an element, is not what you expect when you define the function.
You should use event.target for catch the element clicked
var childElements = document.getElementsByClassName('item');
var buttonElement = document.getElementsByClassName('delete');
var _handler = function(e) {
e.target.parentNode.parentNode.removeChild(e.target.parentNode);
}
function deleteItem(buttonsClass, childClass) {
for (var i=0;i<buttonsClass.length;i++) {
buttonsClass[i].addEventListener('click', _handler, false);
}
}
deleteItem(buttonElement, childElements);
-- edit --
If you want to use the original approach, then you can solve it in this way:
function deleteItem(buttonsClass, childClass) {
for (var i=0;i<buttonsClass.length;i++) {
(function(child) {
buttonsClass[i].addEventListener('click', function(e) {
child.parentNode.removeChild(child);
}, false);
})(childClass[i]);
}
}
With encapsulation (function(encapsulatedChild) { })(child) you can store the value of child in a context that does not change during the next cycle.
Looks like you want to bind a click event to delete buttons, and on that event delete that item.
You need to fetch the child classes individual buttonsClass elements.
function deleteItem( childElements )
{
Array.prototype.slice.call( childElements ).forEach( function( item ){
var deleteChildren = item.getElementsByClassName( "delete" );
Array.prototype.slice.call( deleteChildren ).forEach( function( deleteBtn ){
deleteBtn.addEventListener('click', function()
{
this.parentNode.removeChild( this );
}, false);
});
});
}
or even more simply, just pass the list of buttons on clicking which parent item will be deleted
function deleteItem( buttonElement )
{
Array.prototype.slice.call( buttonElement ).forEach( function( button ){
button.addEventListener('click', function()
{
this.parentNode.removeChild( this );
}, false);
});
}
Ok, so I have been trying for a few days now to figure out how to detect a user click, and assign new properties to a variable. I have attempted this in a few different ways most of them however not working.
So far I have this, which is pretty self explainitory.
var settings = {
objSlideTrigger: '#one', // link button id
objSlidePanel: '#content-one' // slide div class or id
};
if(document.getElementById('#one').click) {
var setup = settings;
setup.objSlideTrigger = '#one',
setup.objSlidePanel = '#content-one'
};
if(document.getElementById('#two').click) {
var setup = settings;
setup.objSlideTrigger = '#two',
setup.objSlidePanel = '#content-two'
};
when the user clicks a href on the page it I want it to be detected by the javascript and, for the correct setup to be placed within the settings var for use by the rest of the code.
I have two questions really the first being, I will have to duplicate the conditional statement at least ten times so is there anyway to condense/simplify the code.
secondly,When detecting a Href click in javascript do i have to assign an onclick value to the actual element in the html?
thanks again.
With jQuery
Assuming you're wanting to use jQuery because you've included it at the top, use:
$(document).on('click', '#one', function( event ) {
//Do Code here
//For #one click event
});
Although, to prevent DRY - keep it more generic by using Classes:
<div class="updatesettings" id="one">One</a>
<div class="updatesettings" id="two">Two</a>
<script>
$(document).on('click', '.updatesettings', function( event ) {
//Do Code here
//For all .updatesettings click event
alert( $(this).attr('id') );
});
</script>
With JavaScript
var OnOneClick = function() {
// Your click handler
};
var OneClick = document.getElementsById("#one");
OneClick.addEventListener('click', OnOneClick, false);
Then to listen for multiple, use by Class (Although not all IE versions can listen for this):
var AwaitedClickEvent = function() {
//Class Click
}
var WaitingClick = document.getElementsByClassName('clickme');
for (var i = 0; i < WaitingClick.length; i++) {
var current = WaitingClick[i];
current.addEventListener('click', AwaitedClickEvent, false);
}
Your Solution
<!-- Links with ID & Content -->
<div class="updatesettings" id="one" data-content="content-one">One</a>
<div class="updatesettings" id="two" data-content="content-two">Two</a>
<script>
/**
* Get the clicked element's ID
* and it's stored data-content string.
**/
$('.updatesettings').on('click', function( event ) {
var Id = $(this).attr('id'),
Content = $(this).data('content'),
setup = settings,
setup.objSlideTrigger = Id,
setup.objSlidePenl = Content;
console.log( setup );
});
</script>
In my page I have many edit buttons each name starts with "edit" and then some id. I want to know any of my edit buttons is clicked or not.
In details, I have form. In form I have many edit buttons which name starts with "edit" , delete buttons which name starts with "delete" and 1 add button. All are submit buttons. form onsubmit I call JavaScript function in which I want if the button is edit confirm("some text") else submit form.
How can I do that in JavaScript?
I think give all these buttons same id and then getElementById but then how con I change?
This is simple using jQuery:
$(':button').click(function() {
// reference clicked button via: $(this)
var buttonElementId = $(this).attr('id');
});
Try it out:
http://jsfiddle.net/7YEay/
UPDATE based on feedback in comments
This is untested/pseudo code:
$(':submit').click(function(event) {
var buttonName = $(this).attr('name');
if (buttonName.indexOf('edit') >= 0) {
//confirm("some text") logic...
}
event.preventDefault();
});
This documentation may be helpful too: http://api.jquery.com/submit/
function MyOnSubmit(e){
e = e || window.event;
// srcElement for IE, target for w3c
var target = e.target || e.srcElement;
if (target.id.indexOf("edit") > -1){
// an edit button fired the submit event
}
}
although i advice you research further to find a better way to handle edit and delete buttons (like making them links with href=editpage.jsp?id=23)
I'm pretty sure you just answered this yourself...
Each starts with "edit", and ends with a unique ID?
So... $(button).attr("id") would give you that. Store it in a variable? Not sure what you're trying to do..
bind click event on all button:
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
if (button.addEventListener) {
button.addEventListener('click', handler, false);
}
else {
button.attachEvent('onclick', handler);
}
}
in your event handler, get the Event object, and then get the target:
function handler(e) {
e = e || window.event;
// srcElement for IE, target for w3c
var target = e.target || e.srcElement;
var id = target.name.substring(4);
/* your code rely on id */
}
I think you might not have phrased your question correctly. If you are using jquery, locating the button is as easy as $('#id'), and if you want to store any information on that button, you can either add an attribute or use jquery.data function.
$('#id').attr("pressed", "true");
Or
$('#id').data('pressed', 'true');