Search code examples
javascriptparameterscallbackcycle

How to pass cycle variable to event callback function using Javascript


I am uploading multiple files using XMLHttpRequest at the same time. I want each file to have its own progress indicator. So, when I get array of files for upload, I initiate upload for each of them inside a for cycle like

for(var i=0; i<files.length; i++)                    
{
  // Create transfer object
  var xhr = new XMLHttpRequest();

  // Attach progress event handler
  xhr.addEventListener('progress', function(e) { showProgress .... });

 ....
}

The issue is, how to pass correct "i" value to the progress callback function. In case I use "i" like this:

  xhr.addEventListener('progress', function(e) { console.log(i); });

I always get the latest "i" value. In case define it like this:

  xhr.addEventListener('progress', (function(i,e) { console.log(i); })(i));

I get correct I, but I never get the event object "e", so I don't get actual progress. What is correct way of defining it?


Solution

  • Use xhr.upload.progress instead of xhr.progress.

    Create an IIFE, pass i to IIFE, create new progress element having className "progress-" with i concatenated, update current progress element .value to e.loaded within upload progress event. See also Upload multiple image using AJAX, PHP and jQuery

    for(var i=0; i<files.length; i++) {
      // Create transfer object
      (function(curr) {
        // `i` : `curr`
        var xhr = new XMLHttpRequest();
        var progress = document.createElement("progress");
        progress.setAttribute("max", files[curr].size);
        document.body.appendChild(progress);
        progress.className = "progress-" + curr;
        // Attach progress event handler
        xhr.upload.addEventListener("progress", function(e) {
          // update current `progress` `value`
          document.querySelector(".progress-" + curr).value = e.loaded;
        });
        xhr.open("POST", "/path/to/server/");
        xhr.send(new FormData(files[curr]));
      }(i)); // pass `i` to IIFE
    }
    

    jsfiddle https://jsfiddle.net/ytedpcro/1/