订阅完成在完成前调用

时间:2018-03-26 04:24:14

标签: angular rxjs

在我的Angular 5应用程序中,我有一个文件上传组件,它获取页面上放置的文件列表,并为每个文件调用文件上载服务。我想在上传或拒绝所有文件时显示错误列表。

我有这样的事情:

Observable.from(files).subscribe(file=> {
      if (file.size > this.MAX_SIZE) {
        errors.push(`${file.name} is too large.`);
      } else if (this.validFileTypes.indexOf(file.type) < 0) {
        errors.push(`${file.name} is is not a valid image file.`);
      } else {

        this.uploading = true;
        this.uploadingFile = file.name;
        this.fileService.uploadFile(file)
          .subscribe((ev: any) => {
            if (ev.type === HttpEventType.UploadProgress) {
              // blah blah
            } else {
              this.uploading = false;
            }
          }, (err: any) => {
            errors.push(err);
          }
        );          
    });      
},
err => {},
() => {
  if (errors.length) {
    console.log('there were errors');
  }
});

问题是subscribe()完全回调在其他任何事情之前被调用,甚至在它进行主回调之前。

我仍然对这个rx / js的东西感到困惑,所以我确定我再次做了一些愚蠢的事情,但这需要很长时间才能解决。

感谢您阅读此内容:)

更新1

我尝试了@Miller的第一个建议,但现在收到错误:

无法阅读财产&#39;申请&#39;未定义的

我的新方法是:

class DroppedFile {
  constructor(public droppedFile: any, public error: any) { }
}

public dropped(event: UploadEvent) {
  const uploads: any[] = event.files.map(evf => new DroppedFile(evf, null));
  const subs = new Array<any>();

  uploads.forEach(upload => {
    if (upload.droppedFile.fileEntry.isFile) {
      const fileEntry = upload.droppedFile.fileEntry as FileSystemFileEntry;

      fileEntry.file((file: File) => {
        if (file.size > this.MAX_SIZE) {
          upload.error = `${file.name} is too large.  Maximum file size is ${this.MAX_SIZE / 1024}KB.`;
        } else if (this.validFileTypes.indexOf(file.type) < 0) {
          upload.error = `${file.name} is is not a valid image file. You can only upload JPG, GIF & PNG files.`;
        }
      });
    }
  });

  uploads.filter(upload => upload.error == null).forEach(upload => {
    const fileUpload$ = this.fileService.uploadFile(upload.droppedFile, upload.droppedFile.relativePath)
      .catch((err: any, cort: Observable<any>) => {
        upload.error = err;
        return null;
      });

    subs.push(fileUpload$);
  });

  if (subs.length > 0) {
    Observable.forkJoin(...subs)  // BANG!  Cannot read property 'apply' of undefined
      .subscribe((ev: any) => {
        this.uploading = true;
        if (ev.type === HttpEventType.UploadProgress) {
          this.uploadingPercentage = Math.floor(ev.loaded * 100 / ev.total);
        } else {
          this.uploading = false;
        }
     }, (err: any) => {
        // errors.push(err);
      },
        () => {
          // display any errors
          this.getPage(0);
          this.showErrors(uploads);
        });
  } else {
    this.showErrors(uploads);
  }
}

1 个答案:

答案 0 :(得分:0)

问题是您的外部订阅不等待uploadFile来电。

要解决此问题,您可以将fileUpload调用的结果组合到一个数组中。然后使用forkJoin ...

等待他们全部完成
const fileUploads: Observable<any>[] = [];
const errors = [];

files.forEach(file => {
  if (file.size > this.MAX_SIZE) {
    errors.push(`${file.name} is too large.`);
  } else if (this.validFileTypes.indexOf(file.type) < 0) {
    errors.push(`${file.name} is is not a valid image file.`);
  } else {
    const fileUpload$ = this.fileService.uploadFile(file)
      .catch((err: any) => {
        errors.push(err);
      });

    fileUploads.push(fileUpload$);  
  }
});

this.uploading = true;

Observable.forkJoin(...fileUploads).subscribe(
  () => {},
  err => {},
  () => {
    this.uploading = false;
    if (errors.length) {
      console.log('there were errors');
    }
  })
);