在ajax成功函数中更改后无法获得elemens的新id

时间:2017-11-23 07:57:36

标签: javascript jquery ajax

我有一个像这样的ajax代码:

$.ajax({
    type: "post",
    async: false,
    url: "/FindAVet/Search",
    data: '{"vetname":"' + $("#VetName").val() + '","lat":"' + objlatitude + '","lng":"' + objlongitude + '","radius":"' + $("#hdnRadius").val() + '","searchAll":"' + searchAll + '"}',
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function (result) {
        if (result.IsValid == true) {
            $("#divMapContainer").show();
            $("#placeholderServiceagent").html('');
            $("#placeholderServiceagent").show();
            $("#placeholderServiceagent").html(result.Datavalue);
            $("#noserviceagentstatus").hide();

            var arrLoc = result.Locations.split(";");
            var arrInf = result.InfoWindowContents.split(";");

            var source, destination, distance;
            source = $("#SuburbOrPostcode").val();

            var service = new google.maps.DistanceMatrixService();

            var arr2dLoc = [];
            var arr2dInf = [];
            for (var i = 0; i < arrLoc.length; i++) {
                arr2dLoc[i] = arrLoc[i].split(",");
            }
            var j = 1;
            for (var i = 0; i < arrInf.length; i++) {

                arr2dInf[i] = arrInf[i].split(",");
                var strarr2dInf = arr2dInf[i].toString();
                var dom_des = $($.parseHTML(strarr2dInf));
                destination = dom_des.find('.des').text();
                service.getDistanceMatrix({
                    origins: [source],
                    destinations: [destination],
                    travelMode: google.maps.TravelMode.DRIVING,
                    unitSystem: google.maps.UnitSystem.METRIC,
                    avoidHighways: false,
                    avoidTolls: false
                }, function (response, status) {
                    if (status == google.maps.DistanceMatrixStatus.OK && response.rows[0].elements[0].status != "ZERO_RESULTS") {
                        distance = response.rows[0].elements[0].distance.text;
                        var spDistance = $("#distance" + j);
                        spDistance.prepend(distance);

                        var li = $("#" + j);
                        var distancewithoutkmtext = distance.replace(' km', '');
                        li.attr("id", distancewithoutkmtext);

                        j++;
                    } else {
                            alert("Unable to find the distance via road.");
                        }
                    });
            }



            init_map('map_canvas', 18, arr2dLoc, arr2dInf);
        }
        else {
            $("#divMapContainer").hide();
            $("#placeholderServiceagent").hide();
            $("#noserviceagentstatus").show();
        }
        $("#lblServiceAgentStatus").html(result.Message);

    },
    complete: function (data) {

        var elems = $('.storeList').children('li');
        elems.each(function (idx, li) {
            alert($(this).attr("id"));
        });
    }

我已经改变了li标签的id:

 var li = $("#" + j);
 var distancewithoutkmtext = distance.replace(' km', '');
 li.attr("id", distancewithoutkmtext);

输出html的呈现方式如下: enter image description here 这是正确的(新的ID更新)

但是在完整功能中,当我尝试通过调用alert函数来显示<li>标签的id时,会显示id的旧值,如下所示: enter image description here 这是错误的(1,2,3,4 ......是li标签的id的原始值)

你能帮帮我们吗? 任何帮助将不胜感激。 非常感谢你。

2 个答案:

答案 0 :(得分:0)

您正在更改service.getDistanceMatrix()的异步回调函数中的ID。但是您要在原始$.ajax的回调函数中提醒ID,因此第二个回调函数尚未运行。

将带有alert的循环移动到第二个回调函数,您将看到正确的结果。

&#13;
&#13;
$.ajax({
  type: "post",
  async: false,
  url: "/FindAVet/Search",
  data: '{"vetname":"' + $("#VetName").val() + '","lat":"' + objlatitude + '","lng":"' + objlongitude + '","radius":"' + $("#hdnRadius").val() + '","searchAll":"' + searchAll + '"}',
  contentType: "application/json; charset=utf-8",
  dataType: "json",
  success: function(result) {
    if (result.IsValid == true) {
      $("#divMapContainer").show();
      $("#placeholderServiceagent").html('');
      $("#placeholderServiceagent").show();
      $("#placeholderServiceagent").html(result.Datavalue);
      $("#noserviceagentstatus").hide();

      var arrLoc = result.Locations.split(";");
      var arrInf = result.InfoWindowContents.split(";");

      var source, destination, distance;
      source = $("#SuburbOrPostcode").val();

      var service = new google.maps.DistanceMatrixService();

      var arr2dLoc = [];
      var arr2dInf = [];
      for (var i = 0; i < arrLoc.length; i++) {
        arr2dLoc[i] = arrLoc[i].split(",");
      }
      var j = 1;
      for (var i = 0; i < arrInf.length; i++) {

        arr2dInf[i] = arrInf[i].split(",");
        var strarr2dInf = arr2dInf[i].toString();
        var dom_des = $($.parseHTML(strarr2dInf));
        destination = dom_des.find('.des').text();
        service.getDistanceMatrix({
          origins: [source],
          destinations: [destination],
          travelMode: google.maps.TravelMode.DRIVING,
          unitSystem: google.maps.UnitSystem.METRIC,
          avoidHighways: false,
          avoidTolls: false
        }, function(response, status) {
          if (status == google.maps.DistanceMatrixStatus.OK && response.rows[0].elements[0].status != "ZERO_RESULTS") {
            distance = response.rows[0].elements[0].distance.text;
            var spDistance = $("#distance" + j);
            spDistance.prepend(distance);

            var li = $("#" + j);
            var distancewithoutkmtext = distance.replace(' km', '');
            li.attr("id", distancewithoutkmtext);

            j++;
          } else {
            alert("Unable to find the distance via road.");
          }
          var elems = $('.storeList').children('li');
          elems.each(function(idx, li) {
            alert($(this).attr("id"));
          });
        });
      }
      init_map('map_canvas', 18, arr2dLoc, arr2dInf);
    } else {
      $("#divMapContainer").hide();
      $("#placeholderServiceagent").hide();
      $("#noserviceagentstatus").show();
    }
    $("#lblServiceAgentStatus").html(result.Message);
  }
});
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我的代码中已经标记了很多,所以我会尝试在一个例子中解释一下

假设我们可以重写您的代码,使其看起来像这样:

$.ajax({
  type: "post",
  url: "/FindAVet/Search",
  // etc
  success: function successHandler(result) {
    // ...
  },
  complete: function completeHandler() {
    // ...
  }
})

现在,让我们来看看successHadler

function successHandler(result) {
  // Do stuff with html
  // parse result
  // for each location;info pair:
  //   call service.getDistanceMatrix
  //   parse distanceMatrix
  //   modify DOM accordingly
}
在completeHandler中

,大概是,你想要使用修改过的DOM进一步工作,但你不能。 这是因为对service.getDistanceMatrix的调用是异步的。实际上,$.ajax

  1. 发出请求
  2. 等待。 &lt; ---这非常重要。这不是一个简单的等待。你基本上产生执行控制,允许其他代码运行事件循环在这里负责,有关更多详细信息,请参阅https://developer.mozilla.org/cs/docs/Web/JavaScript/EventLoop
  3. 响应到达后,调用成功(我们正在等待,这是放在事件循环队列中)
  4. 成功完成后,呼叫完成(再次,成功后排队)
  5. 发生等待的事情,每次异步调用都会发生这种情况。由于service.getDistanceMatrix是异步的, 在它调用谷歌之后,它就等了。所以,ajax做1,2,3。在3. service.getDistanceMatrix被调用。

    内部的

    service.getDistanceMatrix具有与$ .ajax类似的机制。所以,它再次等待。 现在,如果某些内容等待,则事件循环会在队列中查找它可以在此期间处理的事件。 而且,它现在看到前一个$.ajax有第4步,所以很高兴能够使用它。 几毫秒后,service.getDistanceMatrix也会获取数据并触发你的回调,其中包含:

    //   parse distanceMatrix
    //   modify DOM accordingly
    

    但那已经太晚了,因为completeHandler已经完成了

    那么,如何摆脱这种局面呢?

    最简单的解决方案是将来自completeHandler的代码放在successHandler中。但这不是全部。

    $.ajax({
      type: "post",
      url: "/FindAVet/Search",
      // etc
      success: function successHandler(result) {
        // Do stuff with html
        // parse result
        // for each location;info pair:
        //   call service.getDistanceMatrix
        //   parse distanceMatrix
        //   modify DOM accordingly
    
        completeHandler();
      }
    })
    

    完整处理程序现在仍然不等待getDistanceMatrix的异步调用完成。 我们可以将service.getDistanceMatrix包装成promise以使其异步:

    const service = new google.maps.DistanceMatrixService()
    function getDistanceMatrixAsync(parameters) {
      return new Promise(function(resolve, reject) {
        service.getDistanceMatrix(parameters, function(response, status) {
          if (status == google.maps.DistanceMatrixStatus.OK && response.rows[0].elements[0].status != "ZERO_RESULTS") {
            resolve(response)
          }
          else {
            reject('Unable to find the distance via road.')
          }
        })
      })
    }
    
    // usage:
    
    // outside the loop - this is needed because of the asynchronous code inside the for loop.
    let k = 1
    
    // inside the loop
    getDistanceMatrixAsync({
      origins: [source],
      destinations: [destination],
      travelMode: google.maps.TravelMode.DRIVING,
      unitSystem: google.maps.UnitSystem.METRIC,
      avoidHighways: false,
      avoidTolls: false
    })
    .then(function (response) {
      let j = k;
      distance = response.rows[0].elements[0].distance.text;
      var spDistance = $("#distance" + j);
      spDistance.prepend(distance);
    
      var li = $("#" + j);
      var distancewithoutkmtext = distance.replace(' km', '');
      li.attr("id", distancewithoutkmtext)
    })
    .catch(function (error) {
      alert(error)
    })
    
    k++;
    

    仍然,我们还没有完成。这次电话会议的结果仍然是Promise。仍然是异步调用,completeHandler不会在此等待。但我们几乎就在那里。 我们需要生成一个名为Barrier的同步机制。它没什么特别的,只需等待多个异步任务(promises)完成,一次all 完成后,它会执行你想要的代码。但为此,我们需要创建一个这些Promises的数组!

      // create array for promises just before the for loop
      var promises = []
    
      // add the promise to the array
      var promise = getDistanceMatrixAsync(/* data... */).then(/* stuff with the distance */).catch(/*optional error handling*/)
      promises.push(promise)
    
      // finally, outside and after the for loop, create a barrier!
      Promise.all(promises).then(function() { completeHandler() })
    

    所以这是成功的最短途径!它远非清洁和可维护,但它应该工作。如果您对提高可维护性感兴趣,请打电话给我,我们也可以通过它。

    推荐阅读:

    编辑:

    修正了then getDistanceMatrixAsync中ID的错误。请注意,由于Promise解决方案无法到达,因此它会更改li标记的ID编号逻辑。我建议使用代理ID,即与应用程序中的任何逻辑无关的ID(目前您在列表中使用位置,这会导致耦合)