AngularFire2 - Firebase storage getDownloadURL() - How to return the url for firestore

11,166

Solution 1

This answer is not relevant from Firebase 5.0 release, they removed downloadURL() from upload task. Please refer to doc.

The .downloadURL() observable emits the download URL string once the upload is completed. Then you need to subscribe to get the value.

uploadImage(base64data) {

  const filePath = (`myURL/photo.jpg`);
  //const storageRef = firebase.storage().ref();

  var metadata = {
    contentType: 'image',
    cacheControl: "public, max-age=31536000",
  };

  const ref = this.storage.ref(filePath);
  const task = ref.putString(base64data, 'data_url', metadata);
  const downloadURL = task.downloadURL();

  downloadURL.subscribe(url=>{
     if(url){
         console.log(url);
         //wirte the url to firestore
     }
  })

}

Hope this helps. check this blog for more detail

Solution 2

//observable to store download url
downloadURL: Observable<string>;

task.snapshotChanges().pipe(
    finalize(() => {
        this.downloadURL = fileRef.getDownloadURL();
        this.downloadURL.subscribe(url=>{this.imageUrl = url})
    })
)

refer :https://github.com/ReactiveX/rxjs/blob/master/doc/observable.md

Solution 3

Nesting subscriptions is an antipattern so instead of subscribing in finalize you should use last + switchMap or concat + defer.

last + switchMap

task.snapshotChanges().pipe(
  last(),
  switchMap(() => fileRef.getDownloadURL())
).subscribe(url => console.log('download url:', url))

concat + defer

concat(
  task.snapshotChanges().pipe(ignoreElements()),
  defer(() => fileRef.getDownloadURL())
).subscribe(url => console.log('download url:', url))

Solution 4

.downloadURL() doesn't works longer anymore, you need to use .getDownloadURL() combined with finalize() like so:

.html file

<input type="file" (change)="uploadFile($event)">

.ts file

import {
  AngularFireStorage,
  AngularFireStorageReference,
  AngularFireUploadTask
} from '@angular/fire/storage';
import { Component } from '@angular/core';
import { finalize } from 'rxjs/operators';

@Component({
  selector: 'app-upload',
  templateUrl: './upload.component.html',
  styleUrls: ['./upload.component.scss']
})
export class UploadComponent {
    constructor(private angularFireStorage: AngularFireStorage) {}

    public uploadFile(event: any): void {
        for (let i = 0; i < event.target.files.length; i++) {
            const file = event.target.files[i];
            const fileRef: AngularFireStorageReference = this.angularFireStorage.ref(
              file.name
            );
            const task: AngularFireUploadTask = this.angularFireStorage.upload(
              file.name,
              file
            );
            task
                .snapshotChanges()
                .pipe(
                finalize(() => {
                    fileRef.getDownloadURL().subscribe(downloadURL => {
                        console.log(downloadURL);
                    });
              })
          )
          .subscribe();
       }
   }
}  

Also, note the @angular/fire, it's because all AngularFire2 package is moving into @angular/fire and this is the recommended way to use from now onwards.

Share:
11,166
Admin
Author by

Admin

Updated on June 12, 2022

Comments

  • Admin
    Admin about 2 years

    I've been going through the angularfire2 documentation to retrieve a downloadURl from storage. I'm hoping I'm missing something simple here.

    The documentation states:

    @Component({
      selector: 'app-root',
      template: `<img [src]="profileUrl | async" />`
    })
     export class AppComponent {
       profileUrl: Observable<string | null>;
       constructor(private storage: AngularFireStorage) {
       const ref = this.storage.ref('users/davideast.jpg');
       this.profileUrl = ref.getDownloadURL();
     }
    }
    

    However, once I've uploaded an image I want to return the download url as a string to upload to firestore. I need the download URL for an external service.

    My function

    uploadImage(base64data) {
    
      const filePath = (`myURL/photo.jpg`);
      const storageRef = firebase.storage().ref();
    
      var metadata = {
        contentType: 'image',
        cacheControl: "public, max-age=31536000",
      };
    
      const ref = this.storage.ref(filePath);
      const task = ref.putString(base64data, 'data_url', metadata).then(() => {
    
        var downloadURL = ref.getDownloadURL();
    
      })
    
    }
    

    This uploads the image perfectly fine. However, I would then like to write the download URL to firestore. When console logging my 'downloadURL' variable, I get the following:

    PromiseObservable {_isScalar: false, promise: y, scheduler: undefined}

    The download is inside the promise observable. How do I just get the download URL string as my variable? Once I have that I can sort the firestore updates out.

  • Srinivasan K K
    Srinivasan K K about 6 years
    @Hareesh downloadURL will no longer be attached with Task in recent release of AngularFireStorage.
  • DHRUV GAJWA
    DHRUV GAJWA almost 5 years
    There are some changes brought recently! (I believe so..) Add *** .subscribe() ** after pipe() .... like ... .pipe(finalize(....)).subscribe();
  • Md Rehan
    Md Rehan over 2 years
    thanks this works for me only I changed to url: any