Angular 6 waiting for Observable

Mark

I have the below typescript code.

I tried to make the packageFiles method an Observable so I can wait until it's done before I move on. But somethings not right?

packageFiles(): Observable<any> {

  var filesToSend = [];

  //Loop through files
  this.files.forEach(f => {
    var reader = new FileReader();
    reader.onload = (e) => {
      //
      var fileForUpload = new FileForUpload();
      var encodedString = window.btoa(<string>reader.result);
      fileForUpload.FileValue = encodedString;
      fileForUpload.FileName = f.name;
      fileForUpload.FileType = f.type;

      //
      filesToSend.push(fileForUpload);

      console.log(filesToSend);
    };

    reader.readAsDataURL(f);

  });

  return of(filesToSend);
}

this method calls this then:

uploadFiles() {

  var response = this.packageFiles()
  .subscribe(
    data => {
      console.log("data");
      console.log(data);
    },
    error => {

    }
  );
}
Ingo Bürk

You're synchronously returning an observable of an empty array here, which isn't what you want to do. You need to make sure you first collect the data and then emit on an observable (of emits immediately and then completes).

Let's assume for a second that you only had a single file. In this case, closest to your code would be using a Subject:

packageFiles(): Observable<FileForUpload> {
  const result$ = new Subject<FileForUpload>();
  const reader = new FileReader();
  reader.onload = () => {
    const fileForUpload = new FileForUpload();
    // … do your stuff …

    result$.next(fileForUpload);
    result$.complete();
  };

  // …

  return result$;
}

However, this returns a hot observable, and likely it'd be better here to return a cold observable instead:

packageFiles(): Observable<FileForUpload> {
  return Observable.create(observer => {
    const reader = new FileReader();
    reader.onload = () => {
      const fileForUpload = new FileForUpload();
      // … do your stuff …

      observer.next(fileForUpload);
      observer.complete();
    };

    // …
  });
}

Now you just need to generalize this to multiple files. Let's rename this into packageFile and pass the file as an input:

packageFile(file: File): Observable<FileForUpload> {
  // …
}

Then we can write the actual function as

packageFiles(): Observable<FileForUpload[]> {
  return forkJoin(...this.files.map(file => this.packageFile(file)));
}

… which you can now use by calling

this.packageFiles().subscribe(filesToUpload => { /* … */ });

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related