首页 > 解决方案 > 使用 Firebase 存储和 Firebase 插入/更新用户个人资料图片

问题描述

当用户更新您的个人资料图片时,我需要将他的照片上传到 Firebase 存储并立即检索下载 URL 以更新他的个人资料集合。

在另一种情况下,当用户更新他的个人资料时,他并没有更改他的个人资料图片,所以我没有 imageData 也不需要上传他的图片,只需更新他的个人资料信息。

我的saveProfile()方法:

if (this.profileForm.valid) {
....

  //Check if the user change his picture. If yes, the userProfilePicture has data.
  If (userProfilePicture) {
    //upload the picture to firestorage
      const path = `/profile/${this.profile.id}.jpg`;
      const task =  this.afStorage
        .ref(path)
        .putString(imageData, 'base64', { contentType: 'image/jpeg' });

   // subscribe to download url
      task.downloadURL().subscribe(
        url => {
          //updating profileUrl in the form
          this.profileForm.patchValue({ avatar: url });
      //Doing the update in Firestore
      this.afs.doc(`/profile/${id}`).update(this.profileForm.value);
      });

  }
  Else {
     // just update the profile information
     this.afs.doc(`/profile/${id}`).update(this.profileForm.value);
  }

}

我想避免重复更新代码。有没有更方便的方法来实现这一点?也许,如果我在有可用的 downloadUrl(在 2 种情况下)时进行更新,如下所示:

If (userProfilePicture) {
  //upload the picture
  //subscribe to get the download url
}

//AWAIT for the subscribe to return the download URL and when the download URL is available then update
?? How to do this

//update the profile information with the new or existent download URL
await??? this.afs.doc(`/profile/${id}`).update(this.profileForm.value); 

标签: angulartypescriptfirebase-storageangularfire2rxjs5

解决方案


FYI downloadURL()on task 在 5.0 中已贬值,您需要在上传完成后使用 ref 上的那个;所以你需要保留对它的引用:

const path = `/profile/${this.profile.id}.jpg`;
const ref = this.afStorage.ref(path);
const task =  ref.putString(imageData, 'base64', { contentType: 'image/jpeg' });

task.snapshotChanges().pipe(
  filter(snap => snap.state === storage.TaskState.SUCCESS)
  switchMap(() => ref.getDownloadURL())
).subscribe(url => {
  ...
})

至于减少重复代码,只要使用更新就可以了;因为这只会更新指定的字段。只需将个人资料图片留在 profileForm 之外。

// if there's a profile picture to upload, do so
if (userProfilePicture) {
  const path = `/profile/${this.profile.id}.jpg`;
  const ref = this.afStorage.ref(path);
  const task =  ref.putString(imageData, 'base64', { contentType: 'image/jpeg' });

  task.snapshotChanges().pipe(
    filter(snap => snap.state === storage.TaskState.SUCCESS)
    switchMap(() => ref.getDownloadURL())
  ).subscribe(profilePicture => {
    this.afs.doc(`/profile/${id}`).update({profilePicture});
  })
}

// also just update the rest of the profile, update is non-destructive and only overwrites the fields specified
this.afs.doc(`/profile/${id}`).update(this.profileForm.value); 

推荐阅读