Pregunta

Running into a bit of a funny problem. I have each day of the week hidden upon entry to my html (class="day"). By clicking on the Day, it expands to show everything under that day, by an AJAX call with $.post. This is all working well.

I figure the user may want to look at the whole week at once, so I have a button (id="expander") to show everything. However, when I call the function getSchedule() from within the #expander click, it loops through everything except the $.post in the getSchedule() function. Then it loops through the $.post.

$(document).ready(function()
{ 
    $('.day').click(function(){
        pass = $(this).prop('id');
        getSchedule(pass);
    });

    $('#expander').click(function(ex){
            $('.day').each(function(index){
                    pass = $(this).prop('id');
                    getSchedule(pass);
            });
            $('#expander').text('Hide All Days');
        ex.preventDefault();
        return false;       
    });
});

function getSchedule(elementid){
            dow = elementid.substr(-1);
            url = "standarddayofweek.php?d="+dow;
            $theday = $("#"+elementid);
            console.log("The day is "+$theday.prop('id'));
            $.post(url,function(data){
                    $theday.children('.dayschedule').html(data);
                }, "html"
            )
    }

The console response I get is:

The day is d1 
The day is d2
The day is d3 
The day is d4 
The day is d5 
The day is d6
The day is d7 
XHR finished loading: "http://127.0.0.1/standarddayofweek.php?d=1"
In the post function, the day is d7
XHR finished loading: "http://127.0.0.1/standarddayofweek.php?d=2"
In the post function, the day is d7
XHR finished loading: "http://127.0.0.1/standarddayofweek.php?d=3"
In the post function, the day is d7 
XHR finished loading: "http://127.0.0.1/standarddayofweek.php?d=4"
In the post function, the day is d7 
XHR finished loading: "http://127.0.0.1/standarddayofweek.php?d=5"
In the post function, the day is d7 
XHR finished loading: "http://127.0.0.1/standarddayofweek.php?d=6"
In the post function, the day is d7 
XHR finished loading: "http://127.0.0.1/standarddayofweek.php?d=7"
In the post function, the day is d7 

The watered down HTML:

<div id="expander">Click me to expand</div>

<div id="d1" class="day">
            <div class="dayschedule"></div>
</div>
<div id="d2" class="day">
            <div class="dayschedule"></div>
</div>

....

<div id="d7" class="day">
            <div class="dayschedule"></div>
</div>

What is going on? I have tried adding a delay, to see if the AJAX was happening too fast, but nothing changed.

¿Fue útil?

Solución

Not all browsers will behave synchronously, so async: false is not a comprehensive solution. However, localizing the variables in getSchedule() is.

Try this:

function getSchedule(elementid) {
    var dow = elementid.substr(-1);
    var url = "standarddayofweek.php?d="+dow;
    var $theday = $("#"+elementid);
    console.log("The day is "+$theday.prop('id'));
    $.post(url, function(data) {
        $theday.children('.dayschedule').html(data);
    }, "html");
}

Thus, a closure is formed containing the (formal and informal) vars, which remain available to the inner function (the ajax success handler) when it fires asynchronously, even though the outer function has completed and returned.

Otros consejos

Javascript primarily runs with a single thread of execution see here. What this means to your code:

First off the .each is just a loop. Imagine the ajax requests are sent in a for loop.

for(...)
    $.post();

The ajax callback cannot run until the current execution stops. So your code will go through all of the elements, and log as it does, then the thread is released and the ajax callback can take control.

You should change your program so that you can get a list or batch of content back so that one request is only needed for several elements.

JavaScript is not multi-threaded. You're function must return before asynchronous stuff can happen.

By repeatedly calling $.post without returning the flow of execution to the browser, you are effectively queueing up asynchronous actions which will run when your code has finished.

If, for example, your code were to never return by looping forever, none of your $.posts would ever be invoked.

Thanks to @RobertSmith, the answer was switching from $.post to $.ajax. I just changed:

$.post(url,function(data){
                    $theday.children('.dayschedule').html(data);
                }, "html"
            )

to

$.ajax({
    url: url,
    async:false,
    success: function(data) {
     $theday.next().children('.dayschedule').html(data);
    }
});

Note the async:false; that is what required the switch.

Thanks to everyone for their comments!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top