I am calling JQuery global function on button click
$.fn.editFaculty = function() {
var id = $(this).data('id');
var name = $(this).data('name');
$('#editFacultyName').val(name);
console.log(id); //this works fine
$('#update_btn').click(function (e){
e.preventDefault()
console.log('btn ' + id) //this keeps on adding and sends multiple requests...
})
};
on button click
onclick="$(this).editFaculty();"
On button click this function gets called along with a popup and shows value in popup, then when I click update_button button then I am doing updating value (through ajax but not included in question).
Issue is when I click a button with id=1 (id is not id attribute of html it means the button which corosponds to item which has id 1),
first console.log(id); shows 1 and second console.log('btn' + id) shows btn 1. When I again click on other button with id 2
first console.log(id); shows 2 and second console.log('btn' + id) shows btn 1 btn 2.
$('#update_btn').click(function (e){ gets called twice and then keeps on going to 3, 4, 5, ... until I refresh page.
To answer your question, I ask you (not a question but an imperative) to say to yourself: "How is the event listener function added to the element?"
The response is, via the click method in function body.
The response is, via the onclick property.
So you need to determine how you are going to attach the listener.
Variants of solution
Variant 1get the $('#update_btn').click( up to until the }) outside the body of editFaculty function and get rid of onclick in html!
Variant 2 get rid of click method there and use just the onclick.
Related
I am having a hard time understanding some aspects of JavaScript functions and event handlers.
In the application I'm working on, the user owns a collection of books. Each time he connects, a list of his books is displayed and he has a button to delete a book if he wants to. First, I wrote the following function:
function deleteBook(book_to_delete) {
console.log('Called');
// Other actions to perform to delete the book
}
$(document).on('click', '#user-books-list button.delete', function () {
var self = $(this);
var book_to_delete = self.attr('id').replace('delete-', '');
console.log('Book to delete: ' + book_to_delete);
// If the user wants to delete a book :
// Then display a warning on a modal
$('#confirm-book-deletion').removeClass('hidden');
// If the user clicks 'no' then hide the warning and do nothing else
$('#book-deletion-no').on('click', function () {
// Hiding the modal
$('#confirm-book-deletion').addClass('hidden');
});
// It the user clicks yes, then delete the book
$('#book-deletion-yes').on('click', function () {
// Display the book's id and call deletebook()
console.log('Trigger for ' + book_to_delete);
deleteBook(book_to_delete);
// Hiding the modal
$('#confirm-book-deletion').addClass('hidden');
});
// Make sure we exit this function
return;
});
The problem is that my trigger $('#book-deletion-yes') get fired multiple times.
If I do the following:
Book 1 --> Delete --> Cancel (triggers $('#book-deletion-no'), nothing happens)
Book 2 --> Delete --> Cancel
Book 3 --> Delete --> Confirm
Then instead of only deleting book 3, it deletes books 1, 2, and 3.
The "Book 3" step returns the following :
Book to delete: 3
Trigger for 1
Called
Trigger for 2
Called
Trigger for 3
Called
I changed my code to the following, moving $('#book-deletion-no') and $('#book-deletion-yes') out of the main function, and now it works:
function deleteBook(book_to_delete) {
// Make sure there is indeed a book to delete
if (book_to_delete !== undefined) {
console.log('Called');
// Other actions to perform to delete the book
} else {
console.error('Book id undefined');
}
}
var book_to_delete = undefined;
$(document).on('click', '#user-books-list button.delete', function () {
var self = $(this);
book_to_delete = self.attr('id').replace('delete-', '');
// Then display a warning
$('#confirm-book-deletion').removeClass('hidden');
});
// If the user clicks 'no' then hide the warning and do nothing else
$('#book-deletion-no').on('click', function () {
$('#confirm-book-deletion').addClass('hidden');
// Reset book_to_delete value
book_to_delete = undefined;
});
// It the user clicks yes, then delete the book
$('#book-deletion-yes').on('click', function () {
$('#confirm-book-deletion').addClass('hidden');
// Delete the book
console.log('Trigger for ' + book_to_delete);
deleteBook(book_to_delete);
});
Can someone help me understand why my first attempt did not work, and the main differences between the two? I really don't get why the first code does this weird "loop" through all the former book_to_delete values as this is not even an array.
Thanks
I am reposting here #Teemu's answer to close this topic.
In the first snippet you're adding new click listeners every time the
document is clicked. jQuery on is based on the native
addEventListener, which is capable to attach multiple listeners of the
same type to the elements, the newly-attached event doesn't override
the existing events.
My problem was that I didn't understand how jQuery on worked and was attaching one event on each click, for each book, even if I chose to "cancel" the deletion. Once I finally chose to delete a book, it triggered all of the events... and thus deleted all the books I already clicked on at least once.
jQuery on reference :
https://api.jquery.com/on/
The .on() method attaches event handlers to the currently selected set of elements in the jQuery object.
This method keeps attaching events to the clicked element. It does not replace the event on each click. To detach an event, use the off method.
I'm creating a simple phonebook, that adds person name, last name and phone into a div and into the DOM, with option to delete this div with click event.
I have a class called Phonebook which contain these 2 functions:
//add an event button to all divs inside the DOM
this.deleteBtnEvent = function(){
var _this = this;
//get all the divs that currently on the DOM
var deleteBtn = document.getElementsByClassName('delete');
for (var i = 0; i < deleteBtn.length; i++) {
deleteBtn[i].addEventListener('click', function(e){
_this.removeContact(e.target.parentElement.attributes.index.value);
});
}
};
//remove the div from the array and from the DOM
this.removeContact = function(index){
var contactsHolder = document.getElementById('contacts');
var contact = document.getElementsByClassName('contact');
this._contacts.splice(index, 1);
contactsHolder.removeChild(contact[index]);
//update localstorage
var stringArr = JSON.stringify(this._contacts);
localStorage.setItem('data', stringArr);
console.log('current: ');
console.log(this._contacts);
};
for some reason the addEventListener is firing twice.
first time that the addEventListener is called, the function delete the div from the DOM and the array, the second time the listener is fired, i'm getting an error because the div with the same ID doesn't exist, because its already deleted.
I'm wondering if there's a way to solve this issue.
In addContact(), you call this.deleteBtnEvent(), presumably to bind deletion to the delete button that was just added. In deleteBtnEvent(), however, you're binding an event listener to all delete buttons on the page. This means the following will happen:
Add a contact. A new contact will show up with a delete button that has a listener.
Add a second contact. A new contact will show up with a delete button that has a listener, and a second listener will be added to the first button.
Add a third contact. A new contact will show up with a delete button that has a listener, and a third listener will be added to the first button, and a second listener will be added to the second button.
etc....
So, in deleteBtnEvent(), don't add (duplicate) listeners to all delete buttons. Instead, only add a listener to the delete button that was just created via addContact().
I wrote the code in javascript (jQuery), that allows a user with every click of a button to create a "box" on the web site and to get an alert message after this box was clicked.
It works like this:
1) When the user presses the button "Add (#addBox)" - jQuery appends a new line to the HTML file, that creates the "box" (it looks like a box because of the CSS code).
2) If the user presses the box, it sends out the alert message "Hello".
But if I add multiple boxes and then click on the first one, instead of sending out one alert message, it sends it out as many time as the number of boxes been created.
Example:
1) I have 1 box. By pressing on it, I receive 1 alert message.
2) I have 2 boxes. By pressing on the top one, I receive 2 alert messages.
By pressing on the second one, I receive 1 message.
3) I have 3 boxes. By pressing on the top one, I receive 3 alert messages.
By pressing on the second one, I receive 2 messages.
By pressing on the third one, I receive 1 message.
The function of sending an alert message is looping for some reason.
And so here is the code:
function addBox()
{
$("#addBox").on("click", function () {
$("#addBox").append('<div class="desiredBox">Say Hello</div>');
}
boxCount();
});
}
function boxCount()
{
$(".desiredBox").on("click", function () {
alert("Hello");
});
}
Any ideas, how to make them send only one message each, preventing the function "boxCount()" from looping?
Every time the function boxCount is invoked an event handler is added to existing elements i.e. ".desiredBox". thus you are getting multiple alerts.
As you are creating elements dynamically.
You need to use Event Delegation. You have to use .on() using delegated-events approach.
General Syntax
$(document).on(event, selector, eventHandler);
Ideally you should replace document with closest static container.
Complete code
$("#addBox").on("click", function () {
$("#addBox").append('<div class="desiredBox">Say Hello</div>');
});
$(document).on('click', '.desiredBox', function(){
//Your code
});
Use event delegation so you don't keep adding the click event to .desiredBox over and over again:
$(document).on("click", "#addBox", function () {
$("#addBox").append('<div class="desiredBox">Say Hello</div>');
$(".desiredBox").trigger("click");
});
$(document).on("click", ".desiredBox", function () {
alert("Hello");
});
i am programming in java script to set two button in Gmail page.
i have done it.In that button click event,i have to insert some content.
button creation code:
var btnEncrypt=document.createElement('input');
btnEncrypt.type='button';
btnEncrypt.value='Encrypt';
btnEncrypt.id='btn11';
var btnDecrypt=document.createElement('input');
btnDecrypt.type='button';
btnDecrypt.value='Encrypt';
btnDecrypt.id='btn10';
and the onclick function is,
btnEncrypt.onclick = function()
{
className1 = document.getElementsByClassName('aa')[0].innerHTML;
};
btnDecrypt.onclick = function()
{
className1 = document.getElementsByClassName('bb')[0].innerHTML;
document.getElementsByClassName('bb')[0].innerHTML=decodeData;
};
in first time, i would click the both btnEncrypt and btnDecrypt button it will correctly triggered btnEncrypt.onclick and btnDecrypt.onclick.But again i click the btnDecrypt button are not invoked.
i remove each line from that onclick and check,after i got the problem.
document.getElementsByClassName('bb')[0].innerHTML=decodeData;
using the above line in buttonclick,hereafter only btnDecrypt and btnEncrypt not invoked.
note:both buttons are placed in that bb class using like bb.appendchild(buttons)
How can i resolve that?
Thank u.
For some weird reason i'm getting my confirm box coming up twice. here is my code:
$(".DeleteComment").live("click", function(){
var CommentID = $(this).attr("rel");
var confirm
if (!confirm('Are you sure you want to permanently delete this comment?')){
return false;
}else{
$(this).html("loading").css("color", "#999");
//AJAX HERE
return false;
}
});
Do you load any content dynamically (via ajax)? It could be the case that the click event is bound to the same element twice resulting in the double confirmation.
It happens when we bind event on the elements which are loaded dynamically via AJAX
So for example we are loading some dynamic html content (e.g. dynamic content in modal) on click of the edit form button,
And in that content if we have binded click event on some button e.g. delete button, then every time we click on edit form button, it binds the click event to delete button every time,
And if you have set confirm box on click event of delete button then, it will ask you as many time as it was binded for that click event means here if we have clicked edit form button 5 times then it will asks for your confirmation 5 times.
So for solving that issue you can unbind the event every time before binding event to dynamically loaded element as following :
$(document).off('click', '.DeleteComment').on('click', '.DeleteComment', function () {
if (confirm('Are you sure you want to permanently delete this comment?')){
//Delete process
return true;
}
return false;
}
Or Another way to solve this problem is to add your script in main page, means static page not in dynamically loaded one.
try this:
$_blockDelete = false;
$(".DeleteComment").live("click", function(event){
event.preventDefault();
//event.stopPropagation(); // it is not necessary
if (!$_blockDelete)
{
$_blockDelete =true;
var rconfirm = confirm('Are you sure you want to permanently delete this comment?');
if (rconfirm)
{
$(this).html("loading").css("color", "#999");
var CommentID = $(this).attr("rel");
//AJAX HERE
//return the value "false" the variable "$_blockDelete" once again ajax response
}
}
});
Did you try removing that not-used var confirm?