Search code examples
angularfirebasefirebase-storageangularfire2

uploading file to firebase storage using angularfire


I am using angularfire2 for uploading image to the firebase storage. The upload works just fine though i have trouble in the timing to wait for my code for the download url to be available. Here is the code when file gets picked

 async onFilesAdded(event){
      console.log("file added")
      if (event.target.files.length > 0) {
        const file = event.target.files[0];
        console.log("File name is:" + file.name)

         await this.dataSvc.pushUpload(file).then(
            (res) => {
              console.log("download url is::" + this.dataSvc.downloadURL)
            },
            (err) => console.log("fail to upload file:" + err)
          )


      }
    }

My service implements it as below

 pushUpload(file: File) {
    const filePath = '/' + file.name;
    const fileRef = this.storage.ref(filePath);

    return new Promise<any>((resolve, reject) => {
         const task = this.storage.upload(filePath, file);

          task.snapshotChanges().pipe(
      finalize(() => this.downloadURL = fileRef.getDownloadURL() )
   ).subscribe(
        res => resolve(res),
        err => reject(err))
   }
   )
  }

I am hoping to wait until the promise is resolved and i see the download url. But my code does not seems to wait and i get the downloadUrl undefined and after few sec the download url actually shows up in service. So basically my code calling the pushUpload is not waiting for the download to finish.

Another variation where i never get the download url inside finalize

pushUpload(file: File) {
    const path = '/' + file.name;
    const ref = this.storage.ref(path);

    let task = this.storage.upload(path, file);
    let snapshot   = task.snapshotChanges().pipe(
      finalize( async() =>  {
        this.downloadURL = await ref.getDownloadURL().toPromise();
        console.log("download url i got is:" + this.downloadURL)
      }),
    );
  }

Solution

  • The download seems to finish correctly. But you resolve your promise with the first emitted value from the snapshotChanges observable, which does not have the property downloadURL hence the undefined result.

    You should subscribe to the fileRef.getDownloadURL() observable to get your URL.

    pushUpload(file: File) {
        const filePath = '/' + file.name;
        const fileRef = this.storage.ref(filePath);
    
        return new Promise<any>((resolve, reject) => {
            const task = this.storage.upload(filePath, file);
    
            task.snapshotChanges().pipe(
                finalize(() => fileRef.getDownloadURL().subscribe(
                    res => resolve(res),
                    err => reject(err));
                )
            ).subscribe();
        })
    }
    

    The code looks a little bit ugly with the promise approach. I do not know if you could subscribe inside a subscription, i never did this before.

    As soon as the snapshotChanges observable completes the finalize operation triggers and subscribes to the fileRef.getDownloadURL() observable, this observable should emit the URL immediately and resolves the promise.

    And i would recommend to use the observable instead of creating a new promise.