Search code examples
angularfire2

Angularfire multiple upload


I want to upload few images and I have code as below. It returns the download link, but for only one image. How can I get a list of links to uploaded images?

  constructor(private storage: AngularFireStorage, public afs: AngularFirestore, ) {
    this.files = this.afs.collection('files').valueChanges();
  }

  uploadFile(event) {
    // reset the array 
    this.uploads = [];
    const filelist = event.target.files;
    const allPercentage: Observable<number>[] = [];

    for (const file of filelist) {
      const filePath = `${file.name}`;
      const fileRef = this.storage.ref(filePath);
      const task = this.storage.upload(filePath, file);
      const _percentage$ = task.percentageChanges();
      allPercentage.push(_percentage$);

      // observe percentage changes
      this.uploadPercent = task.percentageChanges();

      // get notified when the download URL is available
      task.snapshotChanges().pipe(
        finalize(() => {
          this.downloadURL = fileRef.getDownloadURL();
        })
      ).subscribe();
      // this.downloadURLs.push(this.downloadURL);
    }
  }

uploadFile(files) {
    //console.log(this.uploadService.uploadFile(file));
    this.uploadService.uploadFile(files);
  }
<ion-item>
      <ion-input type="file" (change)="uploadFile($event)" multiple="multiple"></ion-input>
    </ion-item>
    
    <button (click)="onAddItem()" ion-button block>Добавить</button>


Solution

  • Easy way: Clear this.downloadURLs before uploaded, then add url in finalize step

    uploadFile(event) {
        // reset the array 
        this.uploads = [];
        this.downloadURLs = [];
        const filelist = event.target.files;
        const allPercentage: Observable<number>[] = [];
    
        for (const file of filelist) {
          const filePath = `${file.name}`;
          const fileRef = this.storage.ref(filePath);
          const task = this.storage.upload(filePath, file);
          const _percentage$ = task.percentageChanges();
          allPercentage.push(_percentage$);
    
          // observe percentage changes
          this.uploadPercent = task.percentageChanges();
    
          // get notified when the download URL is available
          task.snapshotChanges().pipe(
            finalize(() => {
              fileRef.getDownloadURL().subscribe((url) => { 
                this.downloadURLs = this.downloadURLs.concat([url]);
              });
            })
          ).subscribe();
          // this.downloadURLs.push(this.downloadURL);
        }
      }
    

    Rxjs way: First combine all latest result, then subscribe to assign results. Note: You can use forkJoin too

       import { combineLatest, from } from 'rxjs';
       import { map, filter } from 'rxjs/operators';
    
       ...
    
          uploadFile(event) {
            // reset the array 
            this.uploads = [];
            const filelist = event.target.files;
            const allPercentage: Observable<number>[] = [];
            const downloadUrls$ = filelist.map((file) => {
    
              const filePath = `${file.name}`;
              const fileRef = this.storage.ref(filePath);
              const task = this.storage.upload(filePath, file);
              const _percentage$ = task.percentageChanges();
              allPercentage.push(_percentage$);
    
              // observe percentage changes
              this.uploadPercent = task.percentageChanges();
    
              // get notified when the download URL is available
              return task.snapshotChanges().pipe(
                filter((task) => task.state === this.storage.TaskState.SUCCESS)
                switchMap(() => from(fileRef.getDownloadURL()))
              )
            });
    
            combineLatest(...downloadUrls$)
              .subscribe((urls) => this.downloadURLs = urls)
          }