0

When I am adding values normally it's getting added to json:

Code:

for (var k = 0; k < result.length; k++) {    
    result[k]["sender"] = k;    
}

enter image description here

But when I call value from api and try to store it in result[k]["sender"] then it's not saving in json and values are getting printed on console:

for (var k = 0; k < result.length; k++) {
    var url = "//api";

    $.ajax({
        url: "https://reverse.geocoder.api.here.com/6.2/reversegeocode.json?prox="+result[k]['lat'].toString()+","+result[k]['lon']+"&mode=retrieveAddresses&app_id=***&app_code=***",
        context: document.body,
        success: function (data) {
            console.log(k, typeof data['Response']['View'][0]['Result'][0]['Location']['Address']['Label']);
            result[k]["sender"] = data['Response']['View'][0]['Result'][0]['Location']['Address']['Label'];
        }
    });
}

Error: enter image description here

Can anyone guide me what I'm missing?

L Lawliet
  • 419
  • 1
  • 7
  • 20
  • 1
    Use `let`: `for (let k = 0; k < result.length; k++) {` – Unmitigated Sep 05 '20 at 17:50
  • 1
    Your operaion is ```Asynchronous```. – Vahid Alimohamadi Sep 05 '20 at 17:50
  • @cybercoder That's not the issue. – Unmitigated Sep 05 '20 at 17:51
  • 1
    @hev1 Yes it is, when you are using ```var``` then the ```k``` is the ```k``` of upper scope. when the op is async the ```k``` is more than expected. – Vahid Alimohamadi Sep 05 '20 at 17:55
  • @cybercoder The nature of the intrinsic issue is not necessarily due to asynchronous operations. – Unmitigated Sep 05 '20 at 17:57
  • It is, though: because the operation is asynchronous, `k` can change between the call to `$.ajax` and its `success` handler. It will be `result.length` at the end because the loop finished before the success handler ran. If it weren't asynchronous, the assumption would hold that `k` would have the same value everywhere inside the loop body. Yes, `let` would prevent that - you are both right. – CherryDT Sep 05 '20 at 17:58

1 Answers1

0

Change var k to let k.

k is incremented at each iteration of the loop, and its final value will be result.length at which point the loop stops.

Your loop first runs for result.length times, incrementing k every time, and you start all those requests with $.ajax. Note, you only start them here, as they are asynchronous! That means, the time when they complete and success is called will be later on, and meanwhile the rest of the code will continue running.

So, later on, the requests complete, and they attempt to access result[k]. However, k === result.length at this point (because the loop has long finished running), so result[k] will be undefined.

With let you can make use of a special feature in ES6 where a let variable inside a for statement actually creates two instances of the variable, with the first one actually counting and the second one being reinitialized to the current value of the first and made available to the inner scope (but keeping its value inside the closure). That's a simplification, but the bottom line is that this way each iteration of your loop will have its own k which keeps its value even after the loop advanced.

Note: Your url seems static at the moment, but if it depends on k at some point then it should also be let, otherwise you get the same problem there as well.


An alternative way, for example if you can't use ES6, would be to create a new (function) scope using an IIFE (immediately-executed function expression) into which you pass the variable as argument:

for (var k = 0; k < result.length; k++) {
  (function (k) {
    // Do $.ajax and everything else here
  })(k);
}

Or, you could use forEach (which takes a callback so it will automatically have a new variable every time).

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • Thanks for your answer, the error is gone but my json i.e. `result` is not getting updated. It's not accepting the value of `result[k]["sender"]` any suggestion for that? – L Lawliet Sep 05 '20 at 18:18
  • Maybe you read the value before the requests are done? I don't see anywhere in your code that you wait for it. – CherryDT Sep 05 '20 at 18:19
  • See https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call – CherryDT Sep 05 '20 at 18:19
  • I've added api in the question can you help me where to add `await`? – L Lawliet Sep 05 '20 at 18:23
  • No, the whole code needs to be restructured (everything in your code that depends on the value that is retrieved asynchronously, i.e. also the code that _calls_ this code, and so on). Please read the question I linked and its answers, and fully understand it. You need to learn async programming, you cannot just "add `await`", I'm afraid... – CherryDT Sep 05 '20 at 18:24