jQuery callback function accumulating - javascript

I wrote some code for a custom confirm box that calls a function when confirm button (yes-button) is pressed and passes another function as a parameter and I bind it to 2 different button clicks with different functions as a parameter. For example:
$('#button1').click(function() {
callFunction(function() { alert("test"); });
});
$('#button2').click(function() {
callFunction(function() { alert("test2"); });
});
function callFunction(callback) {
//code to display custom confirm box
console.log(callback);
$('.confirm-box .yes-button').click(function() {
callback();
});
}
Everything happens as expected, confirm box appears and on confirm button click I get a callback function executed and it alerts "test" (or "test2" depending on which button called the confirm box). The problem arises when I click button1 that sends a function that alerts "test", then instead of confirming I cancel that (nothing happens as expected), and then click button2 that passes alert("test2") as a callback function. Now once I press the yes-button instead of alerting just "test2", I get both "test2" and "test" alerts even though that console.log I wrote logs just the function that alerts "test2" at the time of that button2 click. It seems like these callback functions get stacked somewhere, but I don't understand where and why.

The .click() function can add more than one handler to an element, and I think that's what's happening here. Try this:
// ...
$('.confirm-box .yes-button').unbind('click').click(function() {
callback();
});
This removes any previous click handler before applying the new one.

When you execute the code:
$('.confirm-box .yes-button').click(function() {
callback();
});
you are binding an event handler to the .yes-button element. If you run that code twice, it will have two events bound to it. And so on.
One solution is to use .one instead, so that the event handler will be removed after the first time it is fired:
$('.confirm-box .yes-button').one("click", function() {
callback();
});
This of course has issues if there are two confirm boxes open simultaneously or if there are two .yes-button elements, but for a simple use case it works fine.

What is happening is that each time a button is clicked the callFunction method is executing. It runs through that code block and applies an event listener to the $('.confirm-box .yes-button') button. So clicking your button N times will apply the click listener N times as well. One solution is to store the function in a variable.
Not sure what the end goal is, but this is one solution.
Another solution would be to remove buttons event listeners each time.
var functionToCallOnYes = function() {};
$('#button1').click(function() {
functionToCallOnYes = function() {
alert("test");
};
});
$('#button2').click(function() {
functionToCallOnYes = function() {
alert("test2");
};
});
$('.confirm-box .yes-button').click(function() {
console.log(functionToCallOnYes);
functionToCallOnYes();
});

You can do it by setting an identity by classes,
var button = $('.confirm-box .yes-button');
$('#button1').click(function() {
button.removeClass("b").addClass("a");
});
$('#button2').click(function() {
button.removeClass("a").addClass("b");
});
button.click(function() {
if($(this).hasClass("a")){
callBackForButton1();
} else {
callBackForButton2();
}
});
It is a bad practice to stack up the event handler for a single element.

Yes, extra callbacks are getting stacked up. In $('button1').click(f), the function f will be called with no parameters every time button1 is clicked. In this case, f is callFunction-- a function that itself attaches a new handler to any .confirm-box .yes-button element each time it's invoked. So on the Nth click, you should have N-1 alerts.
To make things like this easier, you can refer to functions by name in JavaScript. So if you had function test() { console.log("test"); };, you could write $(".confirm-box").click(test) just once and every click on a .confirm-box from then on would print test to the console.
Usually if you have callbacks whose sole purpose is to call a callback, you can just remove that callback.

Related

How to restart the Jquery events, to avoid the repetition of each one of them?

I have an index page that contains the following events.
<div id="sub_page"></div>
$(document).ready(function () {
$("a.menu_navegacion_abrircaja").on('click', function (ev) {
ev.preventDefault();
var href = “nombrecontrollerEJ/view_ej";
$.post(href, function (data) {
$("#sub_page").html(data);
});
});
});
In it, when you click, load the html contents of subpages in the div sub_page.
In view view view_ej, I bring html code and also, jquery code. The Jquery code of the view that is added to the index div is as follows:
$(document).ready(function () {
$('#modal_establecer_turnos').on('hidden.bs.modal', function () {
alert("hello");
});
});
By clicking on the link that contains the class "menu_navegacion_abrircaja", I get the alert ("hello");
But it turns out that there is a problem, for every time I click on the link, the alert messages are repeated (alert ("hello");). For example, the first time I click on the link that contains the class menu_navegacion_abrircaja, it works fine showing the alert once, but then I click again on the same link it shows me the alert twice, then I do it for the third time, He shows me three times the alert, and so on.
I would like to know how to solve this problem.
Will there be any way to restart the events or handler of the jquery, as are the events click, change, "hidden.bs.modal", etc., in such a way that their repetition of the events is avoided?
I have seen the methods unbind (), bind (), off (), which might be the solution, but if so, how could you apply them?
Maybe you could try something like this in the jQuery code of your subpage:
$(document).ready(function () {
$('#modal_establecer_turnos').off('hidden.bs.modal');
$('#modal_establecer_turnos').on('hidden.bs.modal', function () {
alert(“hello”);
});
});

onclick needs to be double clicked

When using onclick in JavaScript to call the function nowClicked(), I need to click the object twice in order for the alert to show. Below is the code for my function.
function nowClicked() {
$('.object').click(function() {
$('.object').removeClass("clicked");
var myClass = $(this).attr("id");
alert(myClass);
$(this).addClass("clicked");
e.stopImmediatePropagation();
});
};
What is the problem?
Here's what happens the first time you click your button:
nowClicked is called because you've set it up on the button's onclick
nowClicked sets up a jQuery click handler for .object
The code inside the jQuery click handler only runs the next time you click on the button.
It looks like you are mixing up two ways of handling clicks -- one is using the onclick event, and the second is using jQuery. You need to pick one and stick to it instead of using both.
There is no need to put it inside another function,because click is itself handling a callback function.Remove the outer function nowClicked else remove the $('.object').click(function() {.In the second case you may to pass the context as a function argument.
$('.object').click(function() {
$('.object').removeClass("clicked");
var myClass = $(this).attr("id");
alert(myClass);
$(this).addClass("clicked");
e.stopImmediatePropagation();
});

Changing onclick handler for an element after first click

div.onclick = function(data, dom) {
return function() {
if (data.seenAlready == true) { // HACK
$(this).children().toggle();
return;
}
recursiveSearch(data, dom);
// after this onclick, I want to assign it to a toggle like function. no clue how to do it.
}
}(child, mycontainer.appendChild(div));
I'm trying to swap the onclick method after first onclick on a dom element. I've just not had any success, it seems to some sort of closure loss, or something. I'm fine using jQuery.
You have two ways to do this and both ways are by using a jQuery function:
1) Use one API method - this will work just once. You will click it once and then you choose your own second handler and the first one will not fire again e.g.
$(myselector).one(function(){
$(this).click(myotherhandler);
});
Here is the link to this API http://api.jquery.com/one/.
2) You can choose the following way to replace the event handler .
$(myselector).click(function(){
$(this).off();
$(this).click("secondhandler");
});
this will turn the first handler off and will just fire second handler
Check this jsbin:
http://jsbin.com/fekuq/1/edit?html,js,output

disable click event handler for a duration of time

I've already looked at similar questions but the answers provided involve buttons and not div elements. When I click the div element with id click, the click event handler is disabled by unbind() and sets a timer for 2 seconds. After 2 seconds, the click event handler should be enabled again by bind(). The problem is that the click event handler doesn't seem to get "rebound". I am appending text to another div element to check if the click event handler is active.
Here is my JSFiddle.
Another approach to the whole problem is not to bother with unbinding and rebinding and just use a "disabled" flag:
$(document).ready(function(){
var clickDisabled = false;
$('#click').click(function(){
if (clickDisabled)
return;
// do your real click processing here
clickDisabled = true;
setTimeout(function(){clickDisabled = false;}, 2000);
});
});
Try this:
$(document).ready(function(){
$('#click').click(function(){
$('#click').unbind('click');
$('#status').append("unbound ");
setTimeout(
function(){
$('#click').bind('click',function(){
});
$('#status').append("bound ");
},
2000
);
});
});
You misspelled setTimeout and your "bound" message was being appended only on click.
I answer your question but just don't kill yourself :)) Just kidding... Your code is fine just a typo: setTimeOut should be setTimeout (the O should be o)
When you are rebinding the function the second time you are binding just a subset of all your code - all it does it output bound to the status, but it doesn't contain any of the code for doing a timeout a second time.
Also, you will like the .one() function.
I've fixed up your code here: https://jsfiddle.net/eQUne/6/
function bindClick() {
$('#click').one('click', function() {
$('#status').append("bound ");
setTimeout(bindClick, 2000);
});
}
$(document).ready(function(){
bindClick();
});
If I got what you were asking correctly, this should work:
<div id="click" >time out</div>
<div id="status"></div>
$(document).ready(function() {
$('#click').click(unbindme);
$('#status').html('bound');
function unbindme()
{
$('#click').unbind('click');
$('#status').html('unbound');
setTimeout(function(){
alert('here');
$('#status').html('bound');
$('#click').click(unbindme);
}, 2000);
}
}
Check it out here: https://jsfiddle.net/eQUne/

Need to understand how javascript functions are called

This is part of a code. The question is, does this line "$("#b_facetNewChild").button().click(function(){" means that the following should be fired when the button "facetNewChild" is clicked? Because there is no "onClick" function at the button. Also, can you explain briefly, what does it mean to have this nested into another function "newChildFacet()" and how to call it?
Sorry, but I am new to javascript.Thanks!
function newChildFacet()
{
// button click
$("#b_facetNewChild").button().click(function(){
//get selected fId
var $fId=getSfSelectedFIds();
if($fId.length>0 && $fId.split(",").length!=1)
{
messageBox("Tip","Please select <b>ONE</b> as the parent facet. If no facet is selected, the new facet will be created under <b>root</b>.");
return false;
}
//some more stuff here!
});
// newChildFacetDialog
$("#newChildFacetDialog").dialog({
autoOpen: false,
modal: true,
title: "New Child Facet",
buttons: {
"Cancel": function() {
$(this).dialog('close');
},
"Create": function() {
//get data
var $parentId=getSfSelectedFIds();
});
$(this).dialog('close');
}
}
});
}
First, yes it bound as a click event handler, so it'll run when #b_facetNewChild is clicked - you won't see this in source, it's stored elsewhere in the DOM.
You can call it by invoking the click event handlers on that element, like this:
$("#b_facetNewChild").click();
It doesn't matter that it's a nested/anonymous function, all we care about here is it's a click event handler on that element, so you can trigger it any of the following ways:
$("#b_facetNewChild").click();
$("#b_facetNewChild").trigger("click");
$("#b_facetNewChild").triggerHandler("click");
You got it right.
$("#b_facetNewChild").button().click(function(){ ... }) does exactly what you mean. However, you won't see an onclick handler in the HTML, but rather only if you inspect the DOM/JS element itself (for example, by using FireBug).
The fact that this call is located inside a function simply means it will only be called (i.e. callback attached to the button) once the wrapping function is called.

Categories