【问题标题】:How to Upload Photo to Firebase Storage and Insert the Photo URL in Firestore?如何将照片上传到 Firebase 存储并将照片 URL 插入 Firestore?
【发布时间】:2021-06-30 02:33:33
【问题描述】:

我在这个模块中的主要目标是在 Firebase 存储中上传用户的个人资料图片,并将照片 URL 存储在 Firestore(Cloud Firestore)中。

注意:

  1. 我上传的图片只有 JPG 和 PNG 格式。
  2. 这是具有 Ionic 和 Angular 的跨平台应用程序

我尝试以下场景:

  1. 直接将图片推送到Firestore而不上传到Firebase Cloud Storage所以图片的名称被转换为长字符的“data:image,base64” 在其中,我不知道这个场景在我的数据库或系统中是否可以,因为它运行完美,并且图像是可检索的。我希望你能在这种情况下帮助我。

更新错误:

这是用户的字段:

update-profile.component.ts

  userId: string;
  fname: string;
  studentId: string;


  @ViewChild('filePicker') filePickerRef: ElementRef<HTMLInputElement>;
  @Input() showPreview = true;

  //The Selected Image in the File Explorer
  selectedImage: any;


   constructor(private auth: AuthService,
              private afs: AngularFirestore,
              private loadingCtrl: LoadingController,
              private toaster: ToastController,
              private storage: AngularFireStorage,
              private popOverCtrl: PopoverController) { }

  ngOnInit() {

    this.profileEditSub = this.auth.user$.subscribe(user => {
      this.userId = user.userId;
      this.fname = user.userName;
      this.studentId = user.userSchoolId;
      this.selectedImage = user.userPhoto;
    });

  }

  onSubmit(form: NgForm){

    const user = form.value.fname;
    const studentId = form.value.studentId;

    this.onUpdateUser(user, studentId);

  }//

  async onUpdateUser(name: string, studentNo: string){
    const loading = await this.loadingCtrl.create({
      message: 'Updating...',
      spinner: 'crescent',
      showBackdrop: true
    });

    
    loading.present();
    
    const imageUrl = await this.uploadFile(this.userId, this.selectedImage);

    this.afs.collection('user').doc(this.userId).update({
      'userName': name,
      'userSchoolId': studentNo,
      'userPhoto': imageUrl, // Photo URL from Firebase Storage will be saved in here.
      'editedAt': Date.now()
    })
    .then(() => {
      loading.dismiss();
      this.toast('Update Success', 'success');
      this.closePopOver();
    })
    .catch(error => {
      loading.dismiss();
      this.toast(error.message, 'danger');
    })

  }//

  async uploadFile(id, files):Promise<any> {
    if (files && files.length) {
      try {
        const task = await this.storage.ref('images').child(id).put(files[0]);
        return this.storage.ref(`images/${id}`).getDownloadURL().toPromise();
      } catch (error) {
        console.log(error);
      }
    }
  }

  onPickImage() {
    this.filePickerRef.nativeElement.click();
  }

  onFileChosen(event: Event) {
    const pickedFile = (event.target as HTMLInputElement).files[0];

    if (!pickedFile) {
      return;
    }

    const fr = new FileReader();
    fr.onload = () => {
      const dataUrl = fr.result.toString();
      this.selectedImage = dataUrl;
    
    };
    fr.readAsDataURL(pickedFile);
  }

update-profile.component.html

  <!-- For the Image -->
  <div class="picker">
    <img
      class="img"
      [src]="selectedImage"
      *ngIf="selectedImage && showPreview"
    >
  </div>
  <input type="file" accept=".jpg,.png" *ngIf="usePicker" #filePicker (change)="onFileChosen($event)"/>

  <ion-button class="image-btn" (click)="onPickImage()">
    <ion-icon name="camera" slot="icon-only"></ion-icon>
  </ion-button>

  <!-- Other Textual Information -->
  <form #f="ngForm" (ngSubmit)="onSubmit(f)">
    <ion-list lines="full">
      <ion-item>
        <ion-label position="floating">Full Name:</ion-label>
        <ion-input name="fname" required type="text" [(ngModel)]="fname" #userCtrl="ngModel"></ion-input>
      </ion-item>
      <ion-item>
        <ion-label position="floating">Student No:</ion-label>
        <ion-input name="studentId" required type="number" [(ngModel)]="studentId" #studentIds="ngModel"></ion-input>
      </ion-item>

      <ion-button class="ion-margin" type="submit" expand="block" shape="round" [disabled]="!f.valid">Edit User</ion-button>
    </ion-list>
  </form>

【问题讨论】:

  • 我相信你不需要使用 FileReader。你可以直接上传。检查这个:stackoverflow.com/questions/46988902/…
  • 谢谢你。但我想问题是图像没有生成下载网址,因为我检查了变量“uploadedImage”及其未定义。
  • 但是你确认上传成功了吗?你总是需要一个错误回调来捕捉storage.upload中的错误
  • 很遗憾,它没有上传成功。但是我有一个问题,直接在 Firestore 中上传图片好不好,这是我的替代解决方案之一。
  • 我认为直接上传没有问题。我相信它应该像我添加的链接中提到的那样工作

标签: angular firebase ionic-framework google-cloud-firestore


【解决方案1】:

我在您的代码中注意到了一些事情。

  1. 您打算在&lt;input&gt; 标记的选定文件上使用this.selectedImage 变量(来自文件资源管理器的注释),但在下面的行中,您将其重新分配给来自firestore 的图像的存储引用.
this.profileEditSub = this.auth.user$.subscribe((user) => {
  ...
  this.selectedImage = user.userPhoto; // this line
});
  1. 您不需要FileReader.readAsDataURL()(除非您想使用Reference.putString())。根据 Firebase 存储文档,您可以直接上传 File API 对象,只需将其作为参数传递给 storage.ref().put(File)Example from Firebase docs.

建议

  • &lt;img&gt;src 使用一个单独的变量,然后使用另一个变量来存储文件选择器的当前值 (&lt;input type="file" /&gt;)。

  • onFileChosen() 回调仅用于为文件资源管理器中的选定文件分配变量。

update-profile.component.ts

currentImageUrl: string; // to store the downloadUrl of image to be displayed
selectedFiles: Array<File>; // to store selected files in the File Explorer

this.profileEditSub = this.auth.user$.subscribe(async (user) => {
  ...

  /** 
   * you only store the storage reference (user.userPhoto) in firestore, not the download url,
   * so you need to fetch it again
   */
  this.currentImageUrl = await this.storage
    .ref(user.userPhoto)
    .getDownloadURL()
    .toPromise();
});

onFileChosen(event: any) {
    this.selectedFiles = event.target.files; // just assigns the selected file/s in <input> this.selectedFiles
}

async onSubmit() {
    if (this.selectedFiles.length) {
        // Get selected file
        const file = this.selectedFiles[0];

        // Get the fullPath in Storage after upload
        const fullPathInStorage = await this.uploadImage(this.userId, file);

        /**
         * You can now store the fullPathInStorage in firestore
         *
         * afs.update(...)
         */

        // Get the downloadUrl for the src of img
        this.currentImageUrl = await this.storage
            .ref(fullPathInStorage)
            .getDownloadURL()
            .toPromise();
    }
}

async uploadImage(uid, file): Promise<string> {
    /**
     * You can add random number in file.name to avoid overwrites,
     * or replace the file.name to a static string if you intend to overwrite
     */
    const fileRef = this.storage.ref(uid).child(file.name);

    // Upload file in reference
    if (!!file) {
      const result = await fileRef.put(file);

      return result.ref.fullPath;
    }
}

update-profile.component.html

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

<img [src]="currentImageUrl" />

另外,ERR_NAME_NOT_RESOLVED 可能只是由于网络不稳定。

【讨论】:

    猜你喜欢
    • 2019-04-18
    • 2017-06-16
    • 2018-11-06
    • 2021-03-13
    • 2018-12-29
    • 1970-01-01
    • 2018-02-14
    • 2017-11-20
    • 1970-01-01
    相关资源
    最近更新 更多