1

I'm calling an AJAX request inside a for loop, and I'm expecting to use the iterating variable in the callback function, but it's not retaining the caller value, but the current value.

for (i = 1; i <= numRisks; i++){
    var id = window.localStorage['dbIDRisk'+i];
    if ($.isNumeric(id)){
        $.ajax({
            type: "POST",
            encoding:"UTF-8",
            url:'https://www.example.com/myscript.php',
            data: someXdata,
            success: function (data) {
                window.localStorage['Risk'+i+'PDF'] = 1;
            }
        });
    }
}

It's working fine, the only problem is that, for example, if the iteration variable i = 1, I'd expect that the localStorage line would be window.localStorage['Risk1PDF'] = 1;, but instead it's window.localStorage['Risk2PDF'] = 1;. So the question is, how can I retain the value of i in the success callback for window.localStorage['Risk'+i+'PDF'] = 1;?

Christian Rodriguez
  • 630
  • 1
  • 8
  • 24

2 Answers2

1

You need to use an IIFE here to save the values.

for (i = 1; i <= numRisks; i++) {
  var id = window.localStorage['dbIDRisk' + i];
  if ($.isNumeric(id)) {
    // Start the IIFE here.
    // The value of i is packed inside this function.
    (function (i) {
      $.ajax({
        type: "POST",
        encoding: "UTF-8",
        url: 'https://www.example.com/myscript.php',
        data: someXdata,
        success: function(data) {
          window.localStorage['Risk' + i + 'PDF'] = 1;
        }
      });
    })(i);
    // End the IIFE here.
  }
}

By the time, the AJAX request is processed here, the i value changes. It's better to wrap it up in an IIFE and give it. Also, while dealing with Synchronous and Asynchronous shared data, you have to be very careful. The value of i outside is synchronous. AJAX can execute anytime when the server responds. It can be at times, the whole loops' AJAX code executes at the same time as well.

Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
0

Using an Immediately-Invoked Function Expression, the simplest and most readable way to enclose an index variable:

for (i = 1; i <= numRisks; i++) {
  var id = window.localStorage['dbIDRisk' + i];
  if ($.isNumeric(id)) {
    (function (i) {
      $.ajax({
        type: "POST",
        encoding: "UTF-8",
        url: 'https://www.example.com/myscript.php',
        data: someXdata,
        success: function(data) {
            window.localStorage['Risk' + i + 'PDF'] = 1;
        }
      });
    })(i);
  }
}

Another method is to use let keyword.ES6 introduces new let keyword that are scoped differently than var-based variables.For example, in a loop with a let-based index, each iteration through the loop will have a new value of i where each value is scoped inside the loop, so your code would work as you expect.

for (let i = 1; i <= numRisks; i++){

}

Another method is to use closures.

Read more about, here.

Community
  • 1
  • 1
Mihai Alexandru-Ionut
  • 47,092
  • 13
  • 101
  • 128