0

I've been trying to loop through an array of filenames (the files are supposed to be all in the same directory on my server) and then, IF file exists, generate some html elements with a download link.

I also create an object with info I need based on the array index.

Since the calls are asynchronous, the moment my success function runs, the for loop has ended and I always get the same index inside the function, so I create several elements with the same download link.

Code:

for(var j = 0; j < attachments.length; j++) {

    var re = /(?:\.([^.]+))?$/;

    dataObj = {
       path: "store//$vendorSettingsDTO.vendorId/assets/pdfs/"+attachments[j].propvalue,
       filename: attachments[j].propvalue.replace(/\.[^/.]+$/, ""),
       extension: re.exec(attachments[j].propvalue)[1]
    }

    jQuery.get('store//$vendorSettingsDTO.vendorId/assets/pdfs/' + attachments[j].propvalue, dataObj)
       .done(function() { 
           var div = document.createElement("div");
           div.classList.add("infoDownload")
           var a = document.createElement("a");
           a.href = dataObj.path;
           var img = document.createElement("img");
           img.src = "store//$vendorSettingsDTO.vendorId/assets/themes/$vendorSettingsDTO.skinname/images/adobe-pdf-icon-vector.png";
           img.width = 70;
           a.appendChild(img);
           a.setAttribute("download",dataObj.filename)
           div.appendChild(a)
           document.getElementById("downloads-wrapper").appendChild(div);         
        }).fail(function() { 
                    console.log("Fail")
    })
}

How can I still make it async and have the correct index for my dataObj?

Lberteh
  • 165
  • 13

1 Answers1

0

The simplest option is to use an Immediately Invoked Function Expression, basically wrap the loop body in a function which takes the index as parameter, that way the index gets "fixed" within the body e.g.

for(var j = 0; j < attachments.length; j++) {
    (function (j) {
        // put work here
    })(j);
}

You could even pass in the data object directly so you don't have to mess with indexes anymore:

for(var j = 0; j < attachments.length; j++) {

    var re = /(?:\.([^.]+))?$/;

    (function (dataObj) {
        // work body
    })({
       path: "store//$vendorSettingsDTO.vendorId/assets/pdfs/"+attachments[j].propvalue,
       filename: attachments[j].propvalue.replace(/\.[^/.]+$/, ""),
       extension: re.exec(attachments[j].propvalue)[1]
    });
}

Alternatively, you could mess with more functional combinatorics so you pair data objects and promises, then convert those pairs into a promise on the pair, and finally collect the array of promises into a promise of array (using $.when).

Masklinn
  • 34,759
  • 3
  • 38
  • 57