Manuela
Manuela

Reputation: 137

Promise within Observable: Not able to return data

I'm using Angular 7 and Typescript and I'm trying to read a json file within a zip file. I can print the correct json output on console, but I'm not able to return the json data from that function. I'm downloading the zip File using another service and an observable and within that observable I'm using a promise (that's what the JSZip library offers) to extract the zip file and read the data of my json file. The code of the function is as follows:

extract-zip.service.ts:

async getJSONfromZip(zip_filename: string, json_filename: string) {
    return this.fileService.downloadResource(zip_filename)
    .pipe(
      map (async (data: any) => {
        return JSZip.loadAsync(data)
          .then((zip: any) => {
            Object.keys(zip.files)
            // iterate over all containing files
            .forEach((filename) => {
            // look for json file
            if (filename === json_filename) {
              return zip.files[filename].async('string')
                .then((fileData: any) => {
                  console.log(fileData);

                  return fileData;
              });
            }
          });
      });
    }))
    .toPromise();
  }

It returns a Promise, but I want to return the content of the json file (fileData). How can I do that? I tried converting it to Promise and also using and returning a class member variable, but nothing works.

Upvotes: 1

Views: 592

Answers (2)

distante
distante

Reputation: 7005

I am not sure why you use it as a promise so I have left everything as observables until the end.

async getJSONfromZip(zip_filename: string, json_filename: string) {
    return this.fileService
      .downloadResource(zip_filename)
      .pipe(
        switchMap(data => from(JSZip.loadAsync(data))), // make the promise a observable
        map(zip => {
          const fileNames = Object.keys(zip.files);
          const fileExist = zipFiles.find( fileName => fileName === json_fileName);
          if (fileExist) {
            return zipFiles[fileName];
          } else {
            return undefined;
          }
        }),
        filter(zipFile => zipFile), // do not process anything if the file is not found
        switchMap(zipFile => from(zipFile.async('string')))
      )
      .toPromise();
  }

const myJson = await getJSONfromZip('something.zip', 'json_name.json');

Be aware that your promise could never be full filled, if you need that then you should remove the filter and throw an exception or similar.

I would recommend use it as observable instead of promise.

Upvotes: 3

Pranay Rana
Pranay Rana

Reputation: 176896

you are not awiting your promise that is problem here , it should be like this

so you wait in function as below

async getJSONfromZip(zip_filename: string, json_filename: string) {
    var promise = this.fileService.downloadResource(zip_filename)
    .pipe(
      map (async (data: any) => {
        return JSZip.loadAsync(data)
          .then((zip: any) => {
            Object.keys(zip.files)
            // iterate over all containing files
            .forEach((filename) => {
            // look for json file
            if (filename === json_filename) {
              return zip.files[filename].async('string')
                .then((fileData: any) => {
                  console.log(fileData);

                  return fileData;
              });
            }
          });
      });
    }))
    .toPromise();

     await promise;
  }

or wait for function

var output = await getJSONfromZip(filename,jsongfilname);

Upvotes: 1

Related Questions