4

I'm working with jQuery's Ajax but in my case I need to store the response in global variables:

var points = Array()
$.get("/data", {"id": 1}, function(data) {
    for (var i=0; i < data.length; i++) {
        points[data[i].someid] = data[i];
    }
alert(points[22].someid.toString()); // it works fine
});

alert(points[22].someid.toString()); // undefined

However when I try to access the variable points outside of the scope of $.get() I just get an undefined object. But I get the right object inside $.get().

What's the best way/standard to manage context and scope in this case?

ccarpenterg
  • 779
  • 2
  • 10
  • 11
  • Possible duplicate of http://stackoverflow.com/questions/6009206/what-is-ajax-and-how-does-it-work – Raynos May 22 '11 at 01:45
  • 3
    I don't have time to write up a proper response, but basically the code in the callback for `$.get` may have not been executed yet (and therefore the variable is undefined) because it is asynchronous -- which means it may run at a later undetermined point in time while the script continues execution. – Cristian Sanchez May 22 '11 at 01:46
  • @Sanchez So should I use **success** and $.ajax() instead? – ccarpenterg May 22 '11 at 01:49
  • @ccarpenterg: No. That's just the nature of AJAX (the A stands for asynchronous) -- it doesn't matter which interface you use. Technically, you could use the `async: false` option to get synchronous behavior but I would advise against it because it could lock up the UI while it is waiting for the HTTP request to complete. – Cristian Sanchez May 22 '11 at 01:53
  • @ccarpenterg, `function(data)` is the success callback in for the `$.get()`. – hyperslug May 22 '11 at 01:54
  • You should call the function that parses the data in the callback you used to set the data. – rid May 22 '11 at 01:54
  • @Sanchez @hyperslug So the variable is there but it's not there when I call it with **alert**. – ccarpenterg May 22 '11 at 02:02
  • Think of it this way: if the server responds in 1 minute, then it's too early to read the results in the second alert. It will take 1 minute before the results will be there, so, before that time, there will be nothing in the array. `$.get()` returns immediately. – rid May 22 '11 at 02:05
  • Where you have `// it works fine` is where you need to use `points`, e.g. bind it to the DOM or whatever. – hyperslug May 22 '11 at 02:15
  • @hyperslug Ok, I understand. Is there any way to ensure the user won't be able to trigger another event until all the points are there? – ccarpenterg May 22 '11 at 02:35
  • @ccarpenterg, no, you'll have to prevent that manually (see my update). Basically the user can keep doing stuff while waiting for the `$.get()` to complete, so try to restrict any actions that might interfere with `points`. – hyperslug May 22 '11 at 02:51

1 Answers1

2

Your scope is fine, but the $.get() runs asynchronously. It starts the call then immediately executes the second alert. When the $.get() completes, it executes the function(data){}. Whatever you were going to use out of that, you need to do in there. If you go to firebug console after all this is over, you should find that alert(points[22].someid.toString()) has what you expect.


You can disable elements in your code to discourage further user action:

var points = Array();

// prevent further user action
$('#actionButton').attr('disabled', true);
// optionally show a loading.gif to let them know the browser is busy

$.get("/data", {"id": 1}, function(data) {
    for (var i=0; i < data.length; i++) {
        points[data[i].someid] = data[i];
    }
    alert(points[22].someid.toString()); // it works fine

    // process points data

    // hide loading.gif
    // re-enable user action
    $('#actionButton').removeAttr('disabled');
});
hyperslug
  • 3,473
  • 1
  • 28
  • 29