JS全局变量未在第一次迭代时设置

时间:2012-11-09 02:00:42

标签: javascript html

我正在尝试在处理某些代码后为全局变量赋值。它没有按计划运作。

我所做的是在两个文本框中输入地址和城市。它进入最后一个函数并调用codeAddress获取地址的坐标。

从那里我发送坐标到setLatLng,它工作正常。但我无法使用getLatLng调用longlats来查看设定值。

如果我添加地址和城市两次,它只会显示一个值。我认为longlats的初始化时间太晚,以至于我没有及时看到正确的值。

有什么建议吗?

相关代码如下。

<script>
var longlats ="";

function setLatLng(x,y){
    longlats = x+","+y;
    alert(longlats) //shows value
}

function getLatLng(){
    alert(longlats);
    return longlats;
    //calling this gives undefined
}

function codeAddress() {

$('#map').show();
var geocoder = new google.maps.Geocoder();
var address = document.getElementById("address").value +"," + document.getElementById("city").value;

geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
    var lat = results[0].geometry.location.lat();
    var lng = results[0].geometry.location.lng();
    locationsall[counter] = new Array();
    locationsall[counter][0] = address;
    locationsall[counter][1] = lat; //has value
    locationsall[counter][2] = lng; //has value
    setLatLng(locationsall[counter][1],locationsall[counter][2]);

counter++;

} 

$(function() {
$("#locationadd").click(function() {
   codeAddress();
   var get = getLatLng();//value is undefined..
  //i want to do stuff with the values in longlats
}
)};

</script>

EDIT1

 $("#locationadd").click(function() {
var address = $("#address").val();
var city = $("#city").val();

if (address =="" || city =="") {
    $("#locationtext").text('*Please enter an address and city');
    return false;
} 
else {
    codeAddress(function(){
    var get = getLatLng();
    var longlat = get.split(",");
    var lat = longlat[0];
    var lng = longlat[1];

    var $tr2 = $('<tr>').css({
            'padding': '4px',
            'background-color': '#ddd'
    }).appendTo('#locationDeals');

    var location = [
            address,
            city
    ];
    locations.push(location);

    for (i = 0; i < 2; i++) {
        var $td2 = $('<td>').appendTo($tr2);
        $('<span>').text(location[i]).appendTo($td2);
        $('<input type="hidden">').attr({
            'name': 'loc[' + ctr + '][' + i + ']',
            'value': location[i]
        }).appendTo($td2);
    }
    var $tdRemoveRow2 = $('<td>').appendTo($tr2);
    $('<a>').attr({
        'href': '#',
        'id': 'submit-button'
    }).text("Remove").click(function() {
    var index2 = $tr2.index();
    $("#locationDeals input[type='hidden']").each(function() {
        this.name = this.name.replace(/\[(\d+)\]/, function(str2, number2) {
          return "[" + (+number2 > index2 - 1 ? number2 - 1 : number2) + "]";
        });
    });

    $tr2.remove();
    var tmp = locations.splice(locations.indexOf(location), 1);
    deleteMarker(tmp);
    return false;
    }).appendTo($tdRemoveRow2);

    ctr++;
    document.getElementById("address").value = "";
    document.getElementById("city").value = "";
    document.getElementById("address").focus();
    $("#locationtext").text('');

    return false;
    });
    } 
});

3 个答案:

答案 0 :(得分:3)

问题是geocoder.geocode是异步的。您无法按照自己的方式执行此操作,因为codeAddress函数将在设置longlats之前返回。只有在Google地图返回结果后,您才需要更改编码样式以使用longlats。

您需要更改以下代码:

$("#locationadd").click(function() {
   codeAddress();
   var get = getLatLng();//value is undefined..
  //i want to do stuff with the values in longlats
}

对此:

$("#locationadd").click(function() {
   codeAddress(function(){
     var get = getLatLng();
     //do stuff with the values in longlats
   });
});

为此,您需要将copyAddress更改为:

function codeAddress(callback) {

  /*
   * Some stuff
   */

  geocoder.geocode( { 'address': address}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      /*
       * Some stuff
       */

      setLatLng(locationsall[counter][1],locationsall[counter][2]);

      callback(); // This is where/when the values are returned
                  // so this is where/when we want to execute code.  
    } 
  })
}

补充说明:

根据您的评论,您似乎仍在尝试这样做:

var val;
codeAddress(function(){
    val = getLatLng();
});
doStuffWith(val);

这不起作用,因为codeAddress在执行getFatLng之前返回。您需要更改编码风格。你需要这样写:

codeAddress(function(){
    val = getLatLng();
    doStuffWith(val);
});

也就是说,您需要将调用codeAddress之后编写的所有代码移动到函数INSIDE codeAddress

原因是代码的执行方式如下:

  • 浏览器输入JAVASCRIPT阶段:

       codeAddress is called
              |
              |
              |--------------> inside codeAddress a request to google maps
              |                is made which registers a callback function
              |                to be executed once it returns.
              v
       codeAddress returns
       note that at this point getLatLng isn't called yet
       this is because the browser haven't made the request
       to google maps yet because it's still executing the
       javascript engine.
              |
              v
       code written after codeAddress is executed
       (remember, the call to google maps still haven't happened yet)
              |
              v
       no more javascript to execute
    
  • javascript阶段结束,BROWSER ENTERS DOM RENDERING PHASE

       The DOM gets updated and drawn on screen if there are any changes.
    
  • DOM渲染结束,浏览器进入网络阶段

       (note: in reality the network layer is asynchronous)
    
       Browser executes pending requests (images, iframes, XMLHttprequest etc.)
       Makes the necessary network connections and begins downloading stuff.
              |
              |
              v
       Browser services completed requests and schedules appropriate events
       (update DOM, trigger onreadystatechange etc.)
       Note that at this point no javascript or DOM updates actually happens.
       The browser does things in a loop, not recursively.
       It is at this point that the google maps request is made.
              |
              v
       No more network operations to service
    
  • 网络阶段结束,浏览器输入JAVASCRIPT PHASE

       google maps request completes, onreadystatechange executes
              |
              |
              |----> inside onreadystatechange the callback to the
              |      google maps API is called
              |             |
              |             '-----> inside the google maps callback getLatLng
              |                     is called, then the callback to codeAddress
              |                     is called.
              |                          |
              |                          '------> inside the callback to
              |                                   codeAddress you can now
              |                                   use the returned values.
              |                                   This is the reason you need
              |                                   to move all your code here.
              v
       no more javascript to execute
    
  • javascript阶段结束,浏览器输入DOM渲染阶段

并且事件循环继续。

如您所见,您不能简单地从codeAddress返回值。相反,您需要在codeAddress中移动代码以使其在正确的时间执行。

答案 1 :(得分:0)

您获得undefined因为在调用getLatLng()时尚未设置longlats的值。

您的函数codeAddress()发出异步请求,因此您需要使其能够接受回调作为参数。

codeAddress(function(longLat){
    // do something with longLat
}); 

声明函数codeAddress时,请确保执行回调并将longLat值传递给它。

check this other answer

答案 2 :(得分:0)

Google地理编码服务进行异步的AJAX调用。当您调用codeAddess()时,它会触发AJAX请求并立即返回。响应尚未收到,因此您的变量尚未设置,但您尝试使用getLatLng()来获取它,这显示了一个空警报框(我想)。您要做的是将回调传递给地理编码功能,然后在那里进行后续工作。例如,

function codeAddress(fn) {
   /* Code here */
   if (status == google.maps.GeocoderStatus.OK){
     /* More code here */
     /* Call callback in the end or after setting*/
     fn();
  }
}

您可以这样设置:

$("#locationadd").click(function() {
   codeAddress(getLatLng);
});