views:

6811

answers:

4

Ok, so that title probably doesn't explain my question well. Hopefully this makes sense. This is also my first application with jQuery, so forgive me if I'm doing something dumb.

I have the following function:

function getRandomImages(limit) {
    imagesArray = new Array();
    $.getJSON('createImageArray.php', {limit: limit}, function(data) {
     $.each(data, function(i) {
      imagesArray[i] = data[i];  //imagesArray is declared globally.
     });
    }); 
}

The getJSON is correctly grabbing the JSON object. It returns something like this:

{"image0":"images/19.10.FBB9.jpg","image1":"images/8.16.94070.jpg","image2":"images/8.14.47683.jpg","image3":"images/8.15.99404.jpg","image4":"images/8.13.20680.jpg","image5":"images/21.12.9A.jpg","image6":"images/8.17.75303.jpg"}

I was debugging and am confident that data[i] correctly contains the image path as grabbed from the JSON object. However, after getRandomImages() is called, I look at my global imagesArray and notice that nothing has been changed. I'm guessing it's creating a copy of the imagesArray instead of grabbing the actual one.

Can someone tell me what I need to do so that my global imagesArray gets updated in the $.each block? Do I need to pass in imagesArray by reference somehow? Sorry, I'm a bit lost.

Thanks for the help.

EDIT: Some background information. I am populating an array of random image locations from the DB. I don't want to load all the images from the db to an array at once, because there are just too many. So, I have a counter which keeps track of where I am in my image array. Once I'm done with an image, I move the pointer to the next image. If I reach the end, I need to grab more random images. That's where the above js function gets called; it calls createImageArray.php which grabs x random images from the db and returns an array. I then want to store those image locations in my global imagesArray.

I'm not sure how I would restructure my code to take .getJSON's asynchronouos nature into account.

+2  A: 

What happens here is that the getJSON is called asynchronously. So the function returns immediately and the code inside it is called at some point later at time. It was only then that the imagesArray would be updated.

You could have the getJSON behave synchronously, but I wouldn't recommend it. Instead I recommend restructuring your code to take into consideration the asynchronous nature of AJAX requests.

EDIT: For making a synchronous request use the asunc option (link). Use the general $.ajax function or set AJAX global options. The reason that I don't recommend this is, that it locks the browser. If your server fails to respond in a timely fashion, the user will not be able to use his/her browser.

It isn't that difficult to restructure your code. Just move your logic for handling image arrays in the callback function. For example instead of:

function getRandomImages(limit) {
    imagesArray = new Array();
    $.getJSON('createImageArray.php', {limit: limit}, function(data) {
        $.each(data, function(i) {
                imagesArray[i] = data[i];  //imagesArray is declared globally.
        });
    }); 
   processImages();
}

do

function getRandomImages(limit) {
    imagesArray = new Array();
    $.getJSON('createImageArray.php', {limit: limit}, function(data) {
        $.each(data, function(i) {
                imagesArray[i] = data[i];  //imagesArray is declared globally.
        });
        processImages();
    }); 
}
kgiannakakis
I believe it is synchronous, since the function is declared as a callback in $.getJSON()
defrex
It is called asynchronously. Fromt he documentation (http://docs.jquery.com/Ajax/jQuery.getJSON): "Note: Keep in mind, that lines after this function will be executed before callback"
Cd-MaN
@kgiannakakis: Hrm, I'm not sure how I'd go about restructuring. Is there a way to have it behave synchronously? What's the reasoning behind not recommending that? Do you have recommendations for how I might restructure?
bryan
Thanks kgiannakakis. The restructuring makes sense, but the problem is that I don't do any image processing. The whole point of the function is to put the data in the array (imagesArray[i] = data[i]). Do you have any recommendations of how I should tackle that? Thanks.
bryan
ah, I see. You didn't mean that he was assigning the array asynchronously, but that he was using it so.
defrex
But the data will finally get into the imagesArray, when the callback completes! Try to use an alert or a trace just after the $.each function. The data should be there. Pay attention not to call the getRandomImages again, before the callback completes!
kgiannakakis
I changed the $.each to for(var i in data) imagesArray[i] = data[i]; and my problem was solved ... not sure how/why that would make a difference though.Thanks kgiannakakis. You've helped me a bunch.
bryan
A: 

try this:

function getRandomImages(limit) {
    imagesArray = new Array();
    $.getJSON('createImageArray.php', {limit: limit}, function(data) {
        $.each(data, function(i, val) {
                imagesArray[i] = val;  //imagesArray is declared globally.
        });
    }); 
}
defrex
Unfortunately, that didn't work. Thanks for trying though.
bryan
A: 

First of all: Why you are using a global variable? That's a bad idea, don't do it. You can share variables between functions within a given namespace like this:

var NAMESPACE = {};
NAMESPACE.example = function() { 

    var myField = '1';

    return { 

        someMethod: function() { 
             return myField;
        }, 

        anotherMethod: function() { 
            return myField;
        } 
    };
}();

Secondly, what do you do after the array is fetched? Do you want to display the images on the page or something? Could you at the img-elements to the page instead of putting them into the array?

Tim Büthe
No, unfortunately I can't just display images on the page. I'm editing the src for an image element that I want to change whenever the user clicks a button.
bryan
+1  A: 

Alright, I didn't understand the problem the first time. It's a little hackey, but without knowing more about your code I'd say when you create your imagesArray create a bool imagesLoaded.

function getRandomImages(limit) {
    imagesArray = new Array();
    imagesLoaded = false;
    $.getJSON('createImageArray.php', {limit: limit}, function(data) {
        $.each(data, function(i) {
                imagesArray[i] = data[i];  //imagesArray is declared globally.
        });
        imagesLoaded = true;
    }); 
}

Then, after you call getRandomImages() put your code into a holding pattern with setTimeout() until imagesLoaded = true. Oh, and maybe put some kind of loading graphic on the page for the user to look at so they don't think your app is busted.

defrex