ndemoreau
ndemoreau

Reputation: 3869

Why does setTimeout not work on an AJAX request?

I have this very simple jQuery function:

$(".milestone-in-tree").live({
    mouseenter: function() {
        setTimeout(
        $.ajax({
            type: "GET",
            url:"/projects/pmnodes/" + $(this).data("pmnode") + "/addbuttons.js"
        }),5000)
    },
    mouseleave: function() {
        $(".grid-btn").delay(800).remove();
    }
});

I want to make it wait 5 secs before sending the AJAX request to the server but it doesn't wait, it just sends it right away. Why?

UPDATE:

Thank you for all the feedbacks. I changed the function as it is suggested in all the answers:

$(".milestone-in-tree").live({
    mouseenter: function() {
        var node = $(this).data("pmnode")
        setTimeout(function() {
        $.ajax({
            type: "GET",
            url:"/projects/pmnodes/" + node + "/addbuttons.js"
        }),5000});
    },
    mouseleave: function() {
        $(".grid-btn").delay(800).remove();
    }
});

But I still get no delay. Is there something I misunderstood? PS: I created the node variable because, for a reason I ignore, $(this) is not accessible anymore inside the SetTimeout anonymous function.

UPDATE 2

Finally, I could manage to get the delay but I realized that the request was still sent to the server after the delay, even if the mouseleave event had been triggered in between...

I could find a workaround. It is totally different. The delay doesn't work anymore but the ajax requests are aborted on mouseleave events, which is what I really needed. For the ones who might be interested, this is the code:

var button_request;
$(".milestone-in-tree").live({
    mouseover: function() {
        var node = $(this).data("pmnode");
        button_request = $.ajax({
                        type: "GET",
                        url:"/projects/pmnodes/" + node + "/addbuttons.js"
                    });
        setTimeout(function() {button_request;},5000)
    },
    mouseleave: function() {
        if (button_request) {
            button_request.abort();
            button_request = null;
                }
        $(".grid-btn").remove();
    }
});

Of course the setTimeout could be removed (as it doesn't work...) but I leave it for clarity.

Thanks everyone.

Upvotes: 4

Views: 9936

Answers (7)

Blazemonger
Blazemonger

Reputation: 92893

Try this:

$(".milestone-in-tree").live({
    mouseenter: function() {
        var pmnode = $(this).data("pmnode"); // cache the data in a variable
        setTimeout( function() { // this function(){...} wrapper is necessary
            $.ajax({
                type: "GET",
                url:"/projects/pmnodes/" + pmnode + "/addbuttons.js"
            })
        },5000)
    },
...

The first argument of a setTimeout() call needs to be either a string (which you really, really shouldn't do) or a self-contained function object.

By putting $.ajax(...) there instead, you're telling JavaScript to (1) run it immediately and (2) set the first argument as whatever the ajax function returns -- which, according to the docs, is a jqXHR object which setTimeout can't do anything with.

Just get in the habit of putting an anonymous function(){...} as the first argument of setTimeout() or setInterval() every time you use it, and you'll be fine.

Upvotes: 7

Richard Neil Ilagan
Richard Neil Ilagan

Reputation: 14747

setTimeout() either accepts a string of Javascript code which it evals (very bad practice, might I add), or a function reference that it calls after a specified time.

What you're doing here is neither --- you're calling a function as a first parameter to setTimeout(). Because of that, it doesn't wait.

You want:

setTimeout(function () {
    $.ajax({});
}, 5000);

It's like the difference between:

setTimeout(foo, 1000);

and

setTimeout(foo(), 1000);

Upvotes: 6

Sarfraz
Sarfraz

Reputation: 382606

You are calling it straight away, put it in function callback:

   setTimeout( function() {
    $.ajax({
        type: "GET",
        url:"/projects/pmnodes/" + $(this).data("pmnode") + "/addbuttons.js"
    })
   } ,5000)

Upvotes: 2

Ram
Ram

Reputation: 144659

it needs a function():

setTimeout(function(){
        $.ajax({
        ...
}, 5000)

Upvotes: 1

Anthony Grist
Anthony Grist

Reputation: 38345

You're calling the $.ajax() function, and passing whatever is returned by that call, to setTimeout(). You need to wrap it in an anonymous function:

setTimeout(function() {
    $.ajax({
        type: "GET",
        url:"/projects/pmnodes/" + $(this).data("pmnode") + "/addbuttons.js"
    })
},5000);

Upvotes: 5

aknosis
aknosis

Reputation: 4308

The code you are passing in is actually being executed, if you want to run code inside the first argument you need to wrap it in a function:

$(".milestone-in-tree").live({
    mouseenter: function() {
        setTimeout(
function(){
        $.ajax({
            type: "GET",
            url:"/projects/pmnodes/" + $(this).data("pmnode") + "/addbuttons.js"
        }),5000);
}
    },
    mouseleave: function() {
        $(".grid-btn").delay(800).remove();
    }
});

Upvotes: 1

Curtis
Curtis

Reputation: 103338

Wrap in an anonymous function:

setTimeout(function(){
        $.ajax({
            type: "GET",
            url:"/projects/pmnodes/" + $(this).data("pmnode") + "/addbuttons.js"
        });
},5000)

Upvotes: 2

Related Questions