Using JsZip to create zip file programmatically

2k views Asked by At

I wanna insert files pdf inside of the zip on loop and after download the file zip.

The problem is when I try to download the file thats came empty. If I printer on console a variable zip, it's have my files..

var zip = new JSZip();
var nomeCliente = "";
this.state.docs.forEach(function(itemDoc, index) {
  var file = new File([this.dataURItoBlob(response.data)], itemComment.comment_file_name, {type: response.mime+"charset=utf-8"});
      zip.folder(itemDoc.person_firstname).folder(itemDoc.category_description).file(itemComment.comment_file_name, file);
}
zip.generateAsync({type:"blob"})
 .then(function(content) {
    FileSaver.saveAs(content, nomeCliente+".zip");
});

1

There are 1 answers

0
David Duponchel On BEST ANSWER

From what I can see in the video you posted in the comments, your code can be summarized as:

var zip = new JSZip();
docs.forEach(function () {                    // 1
  requestComments().end(function () {
    requestCommentFile().end(function () {
      zip.folder(...).folder(...).file(...);  // 2
    })
  });
  triggerDownload(zip);                       // 3
});

HTTP requests are asynchronous: requestComments and requestCommentFile will take time to complete and you need to wait for them before calling triggerDownload. Here, the execution order is 1, 3, 2: you prepare the HTTP requests, trigger the download (with an empty zip file) and then HTTP requests end and fill in the zip object.

To fix that, you must wait for the completion of all requests before calling saveAs.

JSZip accepts promises as content but here each request can lead to multiple zip entries so you can't use it. Instead, use promises and Promise.all.

Which ajax library do you use ? If the result is compatible with ES6 Promises, you can convert your code:

// from
comments.forEach(function () {
  request.post(...)
  .send(...)
  .end(function() {
    zip.file(...);
  });
});

// to
var commentsP = comments.map(function () { // forEach to map
  return request.post(...)                 // return here
  .send(...)
  .then(function() {                       // each time you see a then
    return zip.file(...);                  // ends with a return
  });
});
return Promise.all(commentsP);

In this example, commentsP is a list of promises and Promise.all will transform it into a promise of the list of results. That means once it resolves, all included promises have resolved.

Do that for all ajax requests (don't forget any return, it allow inner promises to be chained). In the end, wait for the top level promise before calling triggerDownload (baixarZip in your video).