0

I have to compress several txt files in a zip that come to me from the response of a service in base64 format.

This is the code to download the zip with its compressed txt files under the "txt" folder:

let zip = new JSZip();
zip.file("readme.txt", "Description content");
let txtFile = zip.folder("txt");
this.selectedItems?.forEach((item) => {
    this.downloadService
    .downloadFile(item.name)
    .subscribe((response) => {
      let base64 = response.output.split(",");
      txtFile.file(item.name, base64[1], {base64: true});
    });
});
zip.generateAsync({type:"blob"})
.then(function(content) {
  // see FileSaver.js
  FileSaver.saveAs(content, "fileTxt.zip");
});

"selectedItems": is an array of objects with several files, which if they exist, will be compressed inside the "txt" folder of the zip file and "item.name", is the property of array of objects with the name of the file..

I have two problems:

1. Dynamic name of the zip file

I need to put a dynamic name to the zip file. For this I created a class attribute where I store the name "fileZipName" (The value of fileZipName, Iassign it in the onInit event of the component).

  zip.generateAsync({type:"blob"})
  .then(function(content) {
      // see FileSaver.js
      FileSaver.saveAs(content, this.fileZipName);
  });

When using the variable "fileZipName" inside the "then", it shows me the following error in browser console:

core.js:6210 ERROR Error: Uncaught (in promise): TypeError: Cannot read properties of undefined (reading 'fileZipName')
TypeError: Cannot read properties of undefined (reading 'fileZipName')

2. Add files to zip

If I give it a fixed name, for example "filesTxt.zip" it works fine, it generates the zip file correctly, it includes the "readme.txt" file in the zip, it adds the "txt" folder in the zip, but inside the "txt" folder does not show the file that I need to compress, the folder "txt" is empty.

"base64[1]", contains the base64 code of the txt file: "VGVzdCBJbmZyYTEw", in fact if I go to an online website to decode it, it returns the txt file correctly.

I don't get any error.

Could you help me? Thank you,

6
  • is your code inside a class? If not, where does fileZipName come from? Commented Apr 28, 2022 at 8:51
  • fileZipName, comes from the onInit event of the same component where I have the zip download method Commented Apr 28, 2022 at 8:54
  • If I print it right inside the zip download method, I don't get the error, but if I print it inside the "then", I get the indicated error. Commented Apr 28, 2022 at 8:56
  • 1
    Replace the tradition function expression to a arrow function expression. So, from function (content) {...} to (content) => {...}. Your function code is running on a different context than the class, hence the property you are trying to find is undefined. Commented Apr 28, 2022 at 8:58
  • Great, the dynamic name, with your suggestion (arrow function) it's working fine, thank you very much, I'm missing point 2. Commented Apr 28, 2022 at 9:09

1 Answer 1

1

For the first problem, I recommend reading adding JavaScript context in order to understand the problem you are having, but in order to fix your issue, just replace the traditional function expression to an arrow function expression, so:

From

zip.generateAsync({type:"blob"})
  .then(function(content) {
    // see FileSaver.js
    FileSaver.saveAs(content, this.fileZipName);
});

To

zip.generateAsync({type:"blob"})
  .then((content) => {
    // see FileSaver.js
    FileSaver.saveAs(content, this.fileZipName);
});

In the first expression, the this keyword is not pointing to the class instance (hence the undefined value), while in the second expression, it is.

For the second problem, I have never used that JSZip but from the documentation, what I understood is that the folder function will just create a folder on the output zip. In order to have the subfiles with it, you need to add them yourself.

let zip = new JSZip();
zip.file("readme.txt", "Description content");

// Option 1 (manually add all the files)
let txtFile = zip.folder("txt").file('file1.txt').file('file2.txt');
// Option 2 (add all subfiles indiscriminately) - Did not test this
let txtFile = zip.folder("txt").file(/.*/);
Sign up to request clarification or add additional context in comments.

1 Comment

Ok, for the first part, I understood the problem and that's fine, for the 2nd part, I'll review it and comment something..., thanks.

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.