0

I'm trying to use an AJAX call to update a bunch of image elements on a page. The list of elements to update is held in an array and the URLs to assign to each image are retrieved from a PHP page via AJAX.

The code I have below doesn't work because imagesArray[i] is undefined when it is called from the callback function in the AJAX call - due to the asynchronous nature of JavaScript presumably.

var imagesArray = document.getElementsByClassName('swappableImages');

for (i = 0; i < imagesArray.length; i++) {
  var requestUrl = "http://example.com/getAnImageURL.php";

  getDataViaAJAX(requestUrl, function(data) {
    alert('img url=' + data.responseText);
    imagesArray[i].src = data.responseText;
  });
}

function getDataViaAJAX(url, callback) {
  var request = window.ActiveXObject ?
    new ActiveXObject('Microsoft.XMLHTTP') :
    new XMLHttpRequest;

  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      request.onreadystatechange = doNothing;
      callback(request, request.status);
    }
  };
  request.open('GET', url, true);
  request.send(null);
}

function doNothing() {}

On reading around it seems that one way to solve this would be to use a closure, however closures are something I've still not managed to get my head around and the examples I have found have just confused me further.

So, how can I update each element in the array as an when the AJAX function returns?


Note that the 'duplicate' question that has been identified is a jQuery version of the question with jQuery specific answers. I am using vanilla JavaScript.

0

1 Answer 1

1

Note: First example/approach - referred to in comments - removed from answer.

You may try this:

var requestUrl = "http://example.com/getAnImageURL.php";

for (i = 0; i < imagesArray.length; i++) {
  (function(j) {
    getDataViaAJAX(requestUrl, function(data) {
      alert('img url=' + data.responseText);
      imagesArray[j].src = data.responseText;
    });
  })(i);
}
Sign up to request clarification or add additional context in comments.

7 Comments

Can you explain what is happening in the suggestion? It doesn;t seem to work either and I now get data.responseText is undefined.
The value of "i" will be undefined because the call back function will execute in a different call stack and has lost the scope of "i". In order to retain the value of i, we need to capture "i" in closure. One way is to use immediately invoked function as created above in second approach.
Second example seems to work perfectly, but I am confused by the syntax. I understand the problem with 'i' being out of scope or otherwise unavailable in my original code, but don't understand how (function(j))...(i) manages to assign the value of i to j. And the first example just didn't work for me at all - the data that is returned from the AJAX call is being lost somehow.
(function(j) { // your code })(i) --- passing "i" as a parameter the value of i is now passed as parameter and bound to a j - variable. "j" is in closure scope and will be available in callback. I have used "j" to avoid ambiguity as "i" is already present in parent scope.
But the opening bracket that encloses the function is closed before the brackets that enclose the 'i'.... so it looks like we defined the function within parenthesis, then separately tag (i) on the end. function(j) {//function code }) then followed by (i) on its own. I'm obviously missing something here, and the fact that your code works makes me think it is probably something really useful that I'm missing.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.