0

The Problem

I'm trying to figure out how to return HTML that I've built from a JSON file with jQuery.

I seem to have gotten returnLocations() to wait until getLocations() is finished so that the variable locationsBody is finalized with information gathered from my .each loop. The trouble (I think) is my not being able to return that variable to output it to my HTML page.

The Question

How can I return the variable locationsBody?

Note

(there may be errors in the below code as I trimmed it down as best I could but I think it should illustrate the problem with or without them)

The jQuery

the global variables

var locationsFull = 'un d fined';
var locationsOpener = '' +
    '<div class="locations-header">places youve been</div>' +
    '<div class="locations-container">' +
        '<div class="locations-nav left">left</div>' +
        '<div class="locations-nav right">right</div>'
;
var locationsBody = '<div class="locations-inner">'; // opening of container
var locationsCloser = '</div>'; // closing of container

the function

function locationsFunction() {
    function getLocations() {
        var wait = $.Deferred();
        var area = 'Area1';
        var counter = 1;
        $.getJSON("locations.json", function(data) {
            $(data.places).each(function() {
                var location = this.location;
                var image = this.image;
                if (this.area === 'Area1') {
                    if (counter == 2) {
                        locationsBody = locationsBody + 
                            '<div class="locations-places">' +
                                '<img src="images/places/' + image + '">' +
                                '<div class="locations-places-image">' + location + '</div>' +
                            '</div></div>'
                        ;
                        counter = 0; // added closing of container, reset to 0
                    } else {
                        locationsBody = locationsBody + 
                            '<div class="locations-places">' +
                                '<img src="images/places/' + image + '">' +
                                '<div class="locations-places-image">' + location + '</div>' +
                            '</div>'
                        ;
                        counter = counter + 1;
                    }
                }
            })
            wait.resolve();
        })
        return wait;
    }
    function returnLocations() {
        locationsFull = locationsOpener + locationsBody + locationsCloser; // works, proven in alert and console.log
        //alert(locationsFull); // works
        console.log(locationsFull); // works
        //return locationsFull; // doesnt work
        //return 'anything'; // doesnt work
    }
    getLocations().then(returnLocations);
}

the call

$(function() {
    $('.locations-body').html(locationsFunction());
})

The JSON File

{"places":[
    {
        "area": "Area1",
        "location": "Downtown",
        "image": "downtown.jpg"
    },
    {
        "area": "Area1",
        "location": "Uptown",
        "image": "uptown.jpg"
    }
]}

The HTML

<div class="locations-body"></div>

Further Note: Questions similar to this have been asked dozens of times on stackoverflow alone and those questions and answers have hundreds of thousands of reads. I have read through all of the top ones and more over the last 2 days. My problem is my inability to thoroughly understand the answers and apply them to my exact situation as seems to be the problem of the dozens (hundreds/thousands?) of people asking these questions and the hundreds of thousands (millions?) of people that have been searching for solutions to asynchronous problems.

3 Answers 3

1

You could just call .html() inside the returnLocations() function if that's viable.

the function

function returnLocations() {
    locationsFull = locationsOpener + locationsBody + locationsCloser;
    $('.locations-body').html(locationsFull);
}

the call

$(function() {
    locationsFunction();
}

Otherwise you'll need to look into callbacks, read this, if you need to do it this way I can update my answer with an example later on.

Sign up to request clarification or add additional context in comments.

5 Comments

Awww man, I'm embarrassed I didn't think of that :D Thank you very much, it works fine now!
And may I ask, does return locationsFull; not work because of something to do with return wait;? I'm wondering if I have a fundamental misunderstanding of return.
Your welcome! It doesn't work because it is after an asynchronous call. That means the rest of the code continues to run. Because of this, locationsFunction() resolves before the return statement is made.
Ohh, I thought I got returnLocations() to wait for getLocations() to complete by using deferred. That should be the only reason I'm able to output the variable with information added from the .each loop inside of the getLocations() function.
As you noticed, yes you got it to wait for the asynchronous call to finish which then triggers returnLocations but the code continued while waiting for it and reached the end of the function, meaning the initial call $('.locations-body').html(locationsFunction()); finished before deffered is used, so nothing gets returned (it doesn't know it should wait). Have a search into asynchronous functions, callbacks, promises etc if you're interested, it's not the easiest thing to explain or understand in short comments, best of luck :)
0

Have you tried

return wait.promise();

instead of returning the Deferred? Then calling like this:

var deferredChain = $.Deferred();
deferredChain.then(getLocations).then(returnLocations);
deferredChain.resolve();

2 Comments

This is more of a comment rather than an answer
Thanks for the reply Andre. I tried to get your answer to work but I need to practise .promise and .resolve more to learn how to implement this in my existing code.
0

I discovered today that simply putting a .done at the end of $.getJSON seems to work just the same and is much easier than using $.Deferred and the associated lines of code to make it work.

function locationsFunction() {
    var area = 'Area1';
    var counter = 1;
    $.getJSON("locations.json", function(data) {
        $(data.places).each(function() {
            var location = this.location;
            var image = this.image;
            if (this.area === 'Area1') {
                if (counter == 2) {
                    locationsBody = locationsBody + 
                        '<div class="locations-places">' +
                            '<img src="images/places/' + image + '">' +
                            '<div class="locations-places-image">' + location + '</div>' +
                        '</div></div>'
                    ;
                    counter = 0; // added closing of container, reset to 0
                } else {
                    locationsBody = locationsBody + 
                        '<div class="locations-places">' +
                            '<img src="images/places/' + image + '">' +
                            '<div class="locations-places-image">' + location + '</div>' +
                        '</div>'
                    ;
                    counter = counter + 1;
                }
            }
        })
    }).done(function() {
        locationsFull = locationsOpener + locationsBody + locationsCloser;
        $('.locations-body').html(locationsFull);
    });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.