0

I have this working code:

<script type="text/javascript">
    $(document).ready(function(){
    $("input").click(function(){
        for (var i=1; i<8; i++)
        {
        var a = "id="+i;
        var b = "#sp"+i;
        ajax(a, b);
        }           
    });     

    function ajax(a, b)
    {
        $.ajax({
        url:"ajax.php",
        type:"get",
        data:a,
        success:function(respond){
            $(b).html(respond);
        }
        });
    };      
    });
</script>


<body>
Numbers: <span id="sp1"></span>|<span id="sp2"></span>|<span id="sp3"></span>|<span id="sp4"></span>|<span id="sp5"></span>|<span id="sp6"></span>|<span id="sp7"></span>
<input type="button" value="Send"/>
</body>

And php:

if (isset($_GET["id"]))
{
    echo $_GET['id']+10;
}

Above code is working. I don't understand why below code isn't working:

$(document).ready(function(){
    $("input").click(function(){
        for (var i=1; i<8; i++)
        {
        var a = "id="+i;
        var b = "#sp"+i;
        $.ajax({
            url:"ajax.php",
            type:"get",
            data:a,
            success:function(respond){
            $(b).html(respond);
            }
        });
        }           
    });               
});

Jquery code ajax as function works well, but without it doesn't work... It is strange for me. Please tell me why.

Cœur
  • 37,241
  • 25
  • 195
  • 267
dmytro
  • 246
  • 8
  • 21
  • 1
    Read about JavaScript closures. – tymeJV Aug 06 '14 at 16:24
  • What errors (if any) does the console show (press F12 to view developer tools)? – Jason Aug 06 '14 at 16:26
  • @Jason - no error, but I see only last element. But when I start script with ajax as function everythink ok, and I see all elements. – dmytro Aug 06 '14 at 16:32
  • Two ways I could envision it working. 1) Just use a separate function (this is probably the smarter way). 2) use a while loop instead of a for loop. Then in the ajax success callback, increment `i` (this is dumb because it's essentially an infinite loop waiting for AJAX to finish). You would also have to account for any AJAX errors to prevent the loop from never completing. – Jason Aug 06 '14 at 16:47

1 Answers1

-1

It's because your a and b variables belong to the scope of the function containing the loop, and the $.ajax function is asynchronous, so the loop will have finished and b will equal #sp7 before even the first AJAX response comes back.

I believe that if you change your code to this, it will work:

$(document).ready(function(){
    $("input").click(function(){ 
        for (var i=1; i<8; i++)
        {
            (function(i) {
                $.ajax({
                    url:"ajax.php",
                    type:"get",
                    data: "id="+i,
                    success:function(respond){
                        $("#sp"+i).html(respond);
                    }
                });
            })(i);
        }           
    });               
});

Side-note: if you're ever looping over an array of items, rather than just looping from 1 to 7 as you're doing here, and have a similar situation, you could use jQuery's $.each() function rather than needing a self-invoking function inside the loop, e.g.:

$.each(someArray, function(i) {
    $.ajax({
        url:"ajax.php",
        type:"get",
        data: "id="+i,
        success:function(respond) {
            $("#sp"+i).html(respond);
        }
    });
});
Matt Browne
  • 12,169
  • 4
  • 59
  • 75
  • 1
    Wouldn't you have the same issue with `i`? – Jason Aug 06 '14 at 16:38
  • This selector $("#sp"+i) doesn't work at all. – dmytro Aug 06 '14 at 16:40
  • @Jason Good point. I changed the code to something I think will work; testing it now... – Matt Browne Aug 06 '14 at 16:43
  • works, but I must learn JS closures – dmytro Aug 06 '14 at 16:48
  • 1
    @mit Yes, learning more about closures should clarify this for you...this link might be a good starting point: http://blog.mixu.net/2011/02/03/javascript-node-js-and-for-loops/. It's all about timing...but the bottom line is that if you create a new function with its own scope on each iteration of the loop (as in both my examples above), the problem is avoided. – Matt Browne Aug 06 '14 at 16:59