【问题标题】:JS global variable not being set on first iteration第一次迭代时未设置 JS 全局变量
【发布时间】:2012-11-09 02:00:42
【问题描述】:

我试图在处理了一些代码后给一个全局变量一个值。它没有按计划工作。

我所做的是在两个文本框中输入地址和城市。它进入最后一个函数并调用获取地址坐标的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>

编辑1

 $("#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;
    });
    } 
});

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    问题是geocoder.geocode 是异步的。您不能按照您的方式进行操作,因为您的 codeAddress 函数将在设置 longlats 之前返回。只有在谷歌地图返回结果后,您才需要更改编码样式以使用 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.  
        } 
      })
    }
    

    补充说明:

    从您的 cmets 看来,您仍在尝试这样做:

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

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

    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 阶段结束,浏览器进入 DOM 渲染阶段

         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 阶段

         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 中以使其在正确的时间执行。

    【讨论】:

    • 是否有任何理由这样做会导致我的表单被提交?我已经编辑了代码以包含我在 codeAddress 回调中所做的事情。
    • #locationadd 是提交按钮吗?
    • 不,提交按钮在它下面。我将整个代码包装在 codeaddress(function(){ 代码中。这可能是导致它的原因吗?eurothermwindows.com/ed/inputform.php
    • 似乎它只是在那里使表单想要发布。不知道为什么
    • &lt;button&gt;s 的默认行为类似于&lt;input type=submit&gt;。你需要防止这种情况。从 onclick 函数返回 false 或调用各种特定于浏览器的 preventDefault 函数
    【解决方案2】:

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

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

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

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

    check this other answer

    【讨论】:

      【解决方案3】:

      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);
      });
      

      【讨论】:

      • 为什么 var val = codeAddress(getLatLng) 不起作用?它似乎试图发布我的表格而不是做正确的事情。我希望能够使用返回的值。
      • 发布表单是一个不同的问题。至于分配给val,正如我提到的,它是异步的。你需要做的:codeAddress(function(){var val = getLatLng()})
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多