0
votes

I'm trying to retrieve the download url for every image stored in Firebase Storage. The url is saved in Firebase Firestore. The following code maps the documents received from snapshotChanges method from Firebase Firestore. For every document I get the download url. But this method returns a promise object. Because of this, the map method finishes before the promise object is returned and this causes data.downloadUrl to be empty.

this.listingCollection = this.db.collection<Listing>('listings');
this.listings = this.listingCollection.snapshotChanges().map(actions => {
  return actions.map(a => {
    const data = a.payload.doc.data() as Listing;
    const id = a.payload.doc.id;
    if (data.path) {
      let storageRef = firebase.storage().ref();
      let spaceRef = storageRef.child(data.path);

      spaceRef.getDownloadURL().then((url) => {
        data.downloadUrl = url;
        console.log(url);
      }).catch((error) => {
      });
    }
    return { id, ...data };
  });
});

I'm using the downloadUrl in the HTML-page like this.

<ng-container matColumnDef="downloadUrl">
  <mat-header-cell *matHeaderCellDef></mat-header-cell>
  <mat-cell *matCellDef="let element">{{element.downloadUrl}}</mat-cell>
</ng-container>

Please help. Thanks.

2
did you try moving the return inside your getDownloadURL()'s then callback? : spaceRef.getDownloadURL().then(url => { data.downloadUrl = url; console.log(url); return { id, ...data }; })JP Lew
Just tried it. Didn't work.Søren Pedersen

2 Answers

0
votes

Found that the downloadUrl is available when uploading the image to Firebase Storage:

addListing(listing) {
 let storageRef = firebase.storage().ref();

 for (let selectedFile of 
  [(<HTMLInputElement>document.getElementById('image')).files[0]]) {
   let path = `/${this.folder}/${selectedFile.name}`;
   let iRef = storageRef.child(path);

   iRef.put(selectedFile).then((snapshot) => {
     listing.image = selectedFile.name;
     listing.path = snapshot.downloadURL;
     return this.listingCollection.add(listing);
   })
 }
}
0
votes

try this code

this.listingCollection = this.db.collection < Listing > ('listings');
        this.listings = this.listingCollection.snapshotChanges()
          .map(actions => {
            return actions.map(async a => {
              const data = a.payload.doc.data() as Listing;
              const id = a.payload.doc.id;
              if (data.path) {
                let storageRef = firebase.storage().ref();
                let spaceRef = storageRef.child(data.path);
                const url = await spaceRef.getDownloadURL();
                data.downloadUrl = url;
                console.log(url);
              }
              return {
                id,
                ...data
              };
            });
          });

it worth to mention that there's an official firebase lib for angular @angular/fire, that what you should use instead of the normal package