Osman
Osman

Reputation: 333

JSON request not working correctly in jQuery Each function

I am using the code below to retrieve the latitude and longitude of a given location if the value has been changed for each div containing the class .event.

The problem I'm having is that only two outcomes occur from this code:

Below is the code I am using:

    $(".button").click(function(){

            data = "";
            $(".event").each(function(){

                original = $(this).find(".address").data("original");
                location = $(this).find(".address").html();
                lat = $(this).find(".lat").html();
                lon = $(this).find(".lon").html();

                if (original !== location) {

                    $.getJSON( "http://nominatim.openstreetmap.org/search?q="+location+"&format=json&polygon=1&addressdetails=1", function(result) {
                        lat = result[0].lat;
                        lon = result[0].lon;
                    });

                }

                data = data + randomNumber() + ": " + lat + " " + lon + ",";

            });

            $(".data").val(data);
            $(".form").submit();

    });

The variable data will contain the lat and lon for each div containing the class event. The values will remain the same unless the address has been changed by the user, at which point they will be retrieved again via a JSON request.

The form should then be submitted.

How could I fix this? Thank you

Upvotes: 0

Views: 83

Answers (2)

James Fancy
James Fancy

Reputation: 39

I think you should call $.getJSON concurrently then deal all result while got all of them.

If $.getJSON is not necessary for a location, you can create a immediate resolving deferred/promise to simulate a async call. So that we can deal with the same type of results (jQuery Promise Object).

Here is code (not test) and comments:

$(".button").click(function() {
    // data = "";
    // unnecessary

    // $(".event").each(function() {
    // use map to get promise objects for every ".event"
    var promises = $(".event").map(function() {
        original = $(this).find(".address").data("original");
        location = $(this).find(".address").html();
        // lat = $(this).find(".lat").html();
        // lon = $(this).find(".lon").html();
        // not need here

        if (original !== location) {
            return $.getJSON("http://nominatim.openstreetmap.org/search?q=" + location + "&format=json&polygon=1&addressdetails=1", function(result) {
                lat = result[0].lat;
                lon = result[0].lon;
            });
        } else {
            // make value type same as json, it's a array of { lat, lon }
            return $.Deferred().resolve([{
                lat: $(this).find(".lat").html(),
                lon: $(this).find(".lon").html()
            }]).promise();
        }

        // data = data + randomNumber() + ": " + lat + " " + lon + ",";
        // do it later, after all promise resolved.
    });

    $.when.apply(null, promises)
        .done(function() {
            // convert arguments to a array
            var args = [].slice.apply(arguments);
            data = args
                .map(function(models) {
                    // convert each model to a string
                    var model = models[0];
                    return randomNumber() + ": " + model.lat + " " + lon;
                })
                // join each part with separator ','
                .join(",");

            // while got data, deal with it
            $(".data").val(data);
            $(".form").submit();
        });
});

Upvotes: 1

Barmar
Barmar

Reputation: 781068

$.getJSON is asynchronous, you can't refer to the result outside the callback function. And you don't want to submit the form until all the AJAX requests are done.

$.getJSON() returns a Deferred. You can make an array of all of them, and use $.when() to wait for them.

$(".button").click(function() {

  var promises = [];
  var data = "";
  $(".event").each(function() {

    var original = $(this).find(".address").data("original");
    var location = $(this).find(".address").html();
    var lat = $(this).find(".lat").html();
    var lon = $(this).find(".lon").html();

    if (original !== location) {
      promises.push($.getJSON("http://nominatim.openstreetmap.org/search?q=" + location + "&format=json&polygon=1&addressdetails=1", function(result) {
        var lat = result[0].lat;
        var lon = result[0].lon;
        data += randomNumber() + ": " + lat + " " + lon + ",";
      }));

    } else {
      data += randomNumber() + ": " + lat + " " + lon + ",";
    }

  });
  $.when.apply($, promises).done(function() {

    $(".data").val(data);
    $(".form").submit();
  });

});

Note that the order of the values in data is unpredictable, since AJAX requests don't necessarily return in the same order they were sent.

You should also get in the habit of declaring your variables as local with var (or let in ES6).

Upvotes: 1

Related Questions