简体   繁体   中英

Javascript/jQuery - waiting until function complete before running the rest

Hi I have a button which when it gets clicked triggers a function. The function does some stuff (reverse geocodes a latitude/longitude) and then fills a hidden form input with a value.

I need the input to have the correct value before the rest of the code I need gets executed, is there a way to do this? At the moment I have

$('.addButton').click(function() { 
    //first run the reverse geocode to update the hidden location input with the readable address
    reversegeocode();
    var location = $("#location").val();//the value I need
    $.post("<?php echo $this->webroot;?>locations/add", {location:location})
        .done(function (data) {
            $("#locationsHolder").html(data);
        });
});

So basically I don't want to get the value from the input and post it via AJAX until I know that the reversegeocode() function has finished

Can anyone please explain how I can go about this. I've read some stuff about deferment but I'm absolutely useless at figuring out Javascript and I'm really struggling.

Thanks

EDIT:

Here's my reversegeocode funciton

function reversegeocode(){
    var lat = $('#lattitude').val();
    var lng = $('#longitude').val();
    var latlng = new google.maps.LatLng(lat, lng);
    geocoder.geocode({'latLng': latlng}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          if (results[0]) {//http://stackoverflow.com/questions/8082405/parsing-address-components-in-google-maps-upon-autocomplete-select
              var address_components = results[0].address_components;
              var components={}; 
                jQuery.each(address_components, function(k,v1) {jQuery.each(v1.types, function(k2, v2){components[v2]=v1.long_name});})
            var output = '';
            var needAcomma = false;
            if(components.route != undefined) {
                output += components.route;
                needAcomma = true;
            }
            if(components.locality != undefined) {
                if(needAcomma) {
                    output += ', ';
                }
                output += components.locality;
                needAcomma = true;
            }
            if(components.administrative_area_level_1 != undefined) {
                if(needAcomma) {
                    output += ', ';
                }
                output += components.administrative_area_level_1;
                needAcomma = true;
            }else if(components.administrative_area_level_2 != undefined) {
                if(needAcomma) {
                    output += ', ';
                }
                output += components.administrative_area_level_2;
                needAcomma = true;
            }else if(components.administrative_area_level_3 != undefined) {
                if(needAcomma) {
                    output += ', ';
                }
                output += components.administrative_area_level_3;
                needAcomma = true;
            }
            $("#location").val(output);
          } else {
            alert('No results found');
          }
        } else {
          alert('Geocoder failed due to: ' + status);
        }
    });
}

Since reversegeocode is a asynchronous method, you need to use a callback based solution. reversegeocode should receive a callback method as a argument and then invoke the callback once the geocoding is completed.

$('.addButton').click(function () {
    //pass a callback to reversegeocode which will get called once the geocoding is completed
    reversegeocode(function (location) {
        //the callback receives the location as a parameter
        $.post("<?php echo $this->webroot;?>locations/add", {
            location: location
        })
            .done(function (data) {
            $("#locationsHolder").html(data);
        });
    });
});

function reversegeocode(callback) {
    var lat = $('#lattitude').val();
    var lng = $('#longitude').val();
    var latlng = new google.maps.LatLng(lat, lng);
    geocoder.geocode({
        'latLng': latlng
    }, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            if (results[0]) { //http://stackoverflow.com/questions/8082405/parsing-address-components-in-google-maps-upon-autocomplete-select
                var address_components = results[0].address_components;
                var components = {};
                jQuery.each(address_components, function (k, v1) {
                    jQuery.each(v1.types, function (k2, v2) {
                        components[v2] = v1.long_name
                    });
                })
                var output = '';
                var needAcomma = false;
                if (components.route != undefined) {
                    output += components.route;
                    needAcomma = true;
                }
                if (components.locality != undefined) {
                    if (needAcomma) {
                        output += ', ';
                    }
                    output += components.locality;
                    needAcomma = true;
                }
                if (components.administrative_area_level_1 != undefined) {
                    if (needAcomma) {
                        output += ', ';
                    }
                    output += components.administrative_area_level_1;
                    needAcomma = true;
                } else if (components.administrative_area_level_2 != undefined) {
                    if (needAcomma) {
                        output += ', ';
                    }
                    output += components.administrative_area_level_2;
                    needAcomma = true;
                } else if (components.administrative_area_level_3 != undefined) {
                    if (needAcomma) {
                        output += ', ';
                    }
                    output += components.administrative_area_level_3;
                    needAcomma = true;
                }
                $("#location").val(output);
                //call the callback
                callback(output);
            } else {
                alert('No results found');
            }
        } else {
            alert('Geocoder failed due to: ' + status);
        }
    });
}

Change reversegeocode to take a callback parameter (also known as a continuation ).

Encapsulate all the stuff that needs to wait for reversegeocode to finish, putting it into an in-place, nameless function.

(Note the similarity to what you're already doing for the click handler.)

With this approach you are also free to add parameters to the callback, which you can use to pass data directly through.

$('.addButton').click(function() { 
    reversegeocode(function(some_data) {
        var location = $("#location").val();//the value I need
        //...stuff...
    });
});

function reversegeocode(callback){
    //...stuff...
    geocoder.geocode({'latLng': latlng}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          //...stuff...
        } else {
          alert('Geocoder failed due to: ' + status);
        }
        callback(some_data);
    });
}

您需要在reversegeocode函数中使用回调函数。

The same exact way as you do ajax :)

$('.addButton').click(function() { 
    reversegeocode().done(function(location) {
        $.post("<?php echo $this->webroot;?>locations/add", {location:location})
            .done(function (data) {
                $("#locationsHolder").html(data);
            });
    });
})

To do this you will have reversegeocode return a jquery deferred promise

function reversegeocode() {
  return $.Deferred(function(d) {
    //do stuff and when it succeeds
    d.resolve(location);
    //or if it fails
    d.reject("something went wrong");
  }).promise();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM