In my Rails app, I am committing a single UI action (changing a select value), but the corresponding function is being called twice. The function is below.
// doc.js
$(document).on("change", "select.class", (function(){
if ($("select.otherSelect").find(":selected").is( ":disabled" ) == false) {
$.ajax({
//Ajax call
});
console.log("Selector was changed")
}
}));
I know the function is being called multiple times because the text "Selector was changed" appears more than once in the JS console when I change the select element only once. Before writing this, changing the select element six times in succession caused the function to be called once, then twice, then four times, then eight times, then sixteen times, then thirty-two times.
Why is this?
I fixed the issue. To start, I had an entire page whose elements were bound by functions in $(document).ready(function() {. This became problematic because I was using the select to asynchronously replace many elements in the page with new elements that needed to be bound by those functions (but weren't, since the binding only happens once).
To get around this, I copied all the content in $(document).ready(function() { into a function docReady() and then called docReady() both inside $(document).ready(function() { and whenever I asynchronously reloaded the content of the page. This strategy caused my error; now I was binding every element of the page, including the select itself!
Now, I've called the binding functions for the select only once in $(document).ready(function() { and I call the binding functions for the asynchronously generated elements once every time select changes its value.
You can try like this:
$(document).on("change", "select.class", (function(){
if($(this).data('clicked')) {
return;
}
if ($("select.otherSelect").find(":selected").is( ":disabled" ) == false) {
$.ajax({
//Ajax call
});
console.log("Selector was changed")
}
$(this).data('clicked', true);
}); //removed here was extra )
Related
I have a container element that is being loaded multiple times to show variable content on a click event through an Ajax request and upon ajax Complete i have some functions being called including a function (A) inside an if statement.
My problem is when function (A) finally gets called, it gets called multiple times depending on how many times the container had been loaded before the if statement is true.
Here is simple version of my code:
$(".button").on("click", function(){
loadContainer();
});
var loadContainer = function(){
$(".container").load(url, function(){
var x = $(".x");
if(x.length>0){
A();
};
});
};
x is an element $(".x") that will be loaded in the container and the function (A) should only be called when that element gets loaded. i.e. $(".x").length>0
if (x.length>0) is true after say 3 times of loading the container then function (A) will be called 3 times then.
is there a way around this or a way to make sure function (A) gets called only once??
Edit:
My full code:
ajaxBtn.on("click", function(e) {
loadContainer(url, curtain, mainContainer, body, links);
});
var loadContainer = function(url, curtain, maincontainer, body, links) {
$(".main-container").load(url + " .main-container > *", function() {
$("#logo").css({
"z-index": "400"
});
mainFun();
curtain.removeClass("full");
links.removeClass("here");
body.removeClass("no-scroll");
clearInterval(timer);
getFlexIndex();
position = 0;
if (vidContainer.length > 0) {
youTubeLazyLoad();
}
});
};
please assume that all the variables are already defined.
It sounds like you are adding the same button click listener numerous times
You should look into how this occurs as there is not enough shown for us to know why. Is it embedded inside another event handler perhaps? Or in a function that gets called numerous times?
A workaround is to remove the click listener before adding a new one
Change
$(".button").on("click"...
to
$(".button").off('click').on("click"...
Simplified scenario:
I have a click event on a button
Inside the event I call a function X
Function X returns a value
Click event changes DOM using received data (actually renders a jQuery Template)
SAMPLE CODE:
$("button").click(function()
{
var response = FunctionX();
doTemplateRendering(response); //(*)
});
function FunctionX()
{
//some code
return some_value;
//The click event has finished, so now make a little adjust to the generated dom (*)
}
The questions are:
Do I have a way to determine when the click stops form FunctionX()?
Or is there a way that doTemplateRendering() triggers something that I can capture from FunctionX() so it doesn't matter if I return a value, because at some point I'm going to be able to execute the extra code that I need
The reason behind this is that this is part of a framework and I can't change the click event.
You can't return a value from a function and then do further processing within the same function. But you can schedule some code to run later using setTimeout():
function FunctionX()
{
//some code
setTimeout(function() {
//The click event has finished, so now make a little adjust to the generated dom (*)
}, 5);
return some_value;
}
JS is single-threaded (if we ignore web-workers), so the function you pass to timeout won't be executed until after the click event finishes.
Alternatively, you can bind a second click handler to the same button and do your extra processing there - jQuery guarantees that event handlers (for the same event and element) will be run in the order that they're bound.
Not sure if this works for you, but couldn't you use a callback function that you pass to FunctionX?
$("button").click(function()
{
var fn = funcion(){response){
doTemplateRendering(response);
}
FunctionX(fn);
});
function FunctionX(fn)
{
//some code
fn(some_value);
//The click event has finished, so now make a little adjust to the generated dom (*)
}
I would do this in JS fiddle, but I can't get the POST echoer to work, so I'll make an example here. Let's pretend that someApi returns "bar"
JS / jQuery
$(function() {
$('button').click(function(event) {
getSomeData();
});
function getSomeData() {
$("div").text("Foo = ");
$.get("someApi", function(i) {
$("div").append(i);
});
};
});
HTML
<div></div>
<button>Click Me</button>
There maybe some typos here, but please ignore them as I've written an example on-the-fly. What happens is when <button> is clicked once, all works well. The AJAX function is called and the <div> is appended when the response comes. If I wait for the response and click again, the <div> is overwritten with Foo = and then appended. The issue comes when the user becomes inpatient and clicks <button> multiple times, spawning multiple AJAX requests. This ends up with "bar" being appended multiple times. Is there a feature within JS / jQuery to avoid sending multiple requests to the same URL? I DON'T mean I want a async = false scenario; I know this would work, but would also slow the application down. I also know I could add an if loop that checks if bar has already been appended. What I'm asking for is a proper JS / jQuery .blockMultipleRequest(); kind of thing.
I don't think that there's a plugin for that. You could use .one() in this way:
function bindButton() {
$('button').one('click', function(event) {
getSomeData();
});
}
function getSomeData()
$("div").text("Foo = ");
$.get("someApi", function(i) {
$("div").append(i);
bindButton();
});
}
$(function() {
bindButton();
});
In function bindButton() you define your event handler with one(). Once button has been clicked event is removed until response of AJAX call, then function bindButton() is called again and event handler gets bound again.
You could use the global AJAX event handlers that jQuery provides and then do stuff depending on the request.
.ajaxSend() when any request starts (the event, jqXHR, and settings properties are sent to the handler, so you can then do URL-specific actions by evaluating settings.url
.ajaxComplete() when any request completes.
You could then use an object that keeps track of AJAX calls per URL, which can consult before sending off another request (e.g. only if it not currently in an active/pending state).
I have 3 <select> menus, each with change events working on them. Break down of the code looks like this:
$(document).ready(function(){
// some code
$("#selectOne").change(function() {
// some code inc ajax request
$("#selectTwo").change(function() {
// some code inc a different ajax request
});
$("#selectThree").change(function() {
// some code inc a yet another ajax request
});
});
});
The problem with the above is that, while selectOne works fine, and selectTwo seems to work fine also, if I change selectThree, the code for both selectTwo AND selectThree fires at the same time. Depending on the sequence of selection of any of the 3 selects, the response of selectThree.change can be to display and hide each of the previous responses, before settling on displaying an incorrect response.
What I'd like to do is this:
$(document).ready(function(){
// some code
$("#selectOne").change(function() {
// some code inc ajax request
});
$("#selectTwo").change(function() {
// some code inc a different ajax request
});
$("#selectThree").change(function() {
// some code inc a yet another ajax request
});
});
In this scenario, selectOne works fine, but selectTwo and selectThree don't respond to change.
Is there a way of correcting any of this, so that as each element is changed, only the correct change event is fired?
It seems that when your document is loaded there is no select elements with id "selectTwo" or "selectThree". Similarly in the first case, there is no "selectThree" when the eventhandler of "selectOne" executes. That's why the corresponding event handlers does not execute. There is two way you can handle this proplem.
1 - Assing handlers when the elements are created.
2 - Use .on() instead of .change():
$('body').on("change", "#selectOne", function () {});
$('body').on("change", "#selectTwo", function () {});
$('body').on("change", "#selectThree", function () {});
I've been stuck on this issue for about 2 days. My code (JSFiddle here) is thus:
var foo = function(){
// The code in here will be execute more and more and more times
$(element).hover(function() {
console.log("buggie code run")
})
}
var sliderShow = $(secondElement).bxSlider({
onAfterSlide:function(currentSlideNumber) {
$.ajax("/echo/html/").done(function() {
foo();
})
}
})
My problem is the code will run more than once. For example, when you hover over the element it will fire the function once, but second time it will fire twice. The third time it will fire 3 times, and so on. Why is this happening? Am I making a basic logic error, or is this JavaScript doing something?
This means you are registering the event more than once, probably on each load. You should do so only once!
Hovering itself calls the function twice once on entry and once on exit.. try
var foo = function(){
$(element).hover(function() {console.log("IN")},function() {console.log("OUT")});
}
But then as ThiefMaster pointed out you are also registering the eventhandler multiple times. In you slider, the second time you will add the event handler again and so on and on.
Look at http://docs.jquery.com/Namespaced_Events