链管操作后如何以角度返回服务中的可观测对象 [英] How to return an observable from service in angular after chaining pipe operations

查看:52
本文介绍了链管操作后如何以角度返回服务中的可观测对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试进行链/管道操作,并从使用角火的角度服务中返回一个Observable.

I'm trying to chain / pipe operations and return an Observable from a Service in angular which uses angular fire.

凭诺言我有这个工作

服务

saveDiploma(diploma: { title: any; description: any; picture: any }) {
        return new Observable(observer => {
            const id = this.db.createId();
            this.storage.ref(`diplomas/${id}/original.jpg`)
                .putString(diploma.picture, 'data_url')
                .then(task => {
                    task.ref.getDownloadURL()
                        .then(url => {
                            const saved = {
                                title: diploma.title,
                                description: diploma.description,
                                url,
                                createdAt: firebase.firestore.FieldValue.serverTimestamp(),
                                createdBy: this.auth.auth.currentUser ? this.auth.auth.currentUser.uid : 'anonymous'
                            };
                            this.db.doc(`diplomas/${id}`)
                                .set(saved)
                                .then(() => {
                                    observer.next(saved);
                                    observer.complete();
                                })
                                .catch(e => observer.error(e));
                        })
                        .catch(e => observer.error(e));
                })
                .catch(e => observer.error(e));
        });
    }

组件

save() {
        this.diplomasService.saveDiploma({
            title: this.diplomaForm.value.title,
            description: this.diplomaForm.value.description,
            picture: this.currentImage
        }).subscribe(diploma => {
            console.log('saved diploma', diploma);
        }, e => console.error('error while saving the diploma', e));
    }

我正在尝试在服务中使用Observables而不是Promises,并通过管道

I'm trying to use Observables in the service instead of Promises and pipe them in order like so

saveDiploma(diploma: { title: any; description: any; picture: any }) {
        const id = this.db.createId();
        const ref = this.storage.ref(`diplomas/${id}/original.jpg`);
        return ref.putString(diploma.picture, 'data_url').snapshotChanges().pipe(
            concatMap(task => {
                console.log('getDownloadURL');
                return from(task.ref.getDownloadURL());
            }),
            concatMap(url => {
                console.log('url', url);
                const saved = {
                    title: diploma.title,
                    description: diploma.description,
                    url,
                    createdAt: firebase.firestore.FieldValue.serverTimestamp(),
                    createdBy: this.auth.auth.currentUser ? this.auth.auth.currentUser.uid : 'anonymous'
                };
                return from(this.db.doc(`diplomas/${id}`).set(saved));
            })
        );
    }

但是在完成上传之前会触发getDownloadURL方法,因此会返回错误 storage/object-not-found .我曾尝试在concatMap(getDownloadURL)之前添加一个finalize或filter(在task.state =='success'上),但是我无法使其正常工作.

but the getDownloadURL method is getting fired before the upload is complete and hence returning an error storage/object-not-found. I've tried adding a finalize or filter (on task.state == 'success') before the concatMap(getDownloadURL) but I have failed getting it to work.

有人知道如何通过管道传递此操作并从中返回一个Observable吗?

Does anyone know how to pipe this operations and return an Observable from them?

我正在使用Angular 8.1.2,Angular Fire 5.2.1和rxjs 6.5.1

I'm using Angular 8.1.2, Angular Fire 5.2.1 and rxjs 6.5.1

推荐答案

根据AngularFire文档 ref.putString(..).snapshotChanges()

According to the AngularFire documentation ref.putString(..).snapshotChanges()

在文件上传过程中发出原始的UploadTaskSnapshot.

Emits the raw UploadTaskSnapshot as the file upload progresses.

所以您的问题是 .snapshotChanges()在文件上传完成之前发出了. concatMap 不仅在完成时还会在源中的每次发射中触发.您应该使用 concat .

So your problem is that .snapshotChanges() emits before the file upload is complete. concatMap gets triggered on every emit from the source not just on complete. You should use concat.

saveDiploma(diploma: { title: any; description: any; picture: any }) {
  const id = this.db.createId();
  const ref = this.storage.ref(`diplomas/${id}/original.jpg`);
  return concat(
    ref.putString(diploma.picture, 'data_url').snapshotChanges().pipe(ignoreElements()),
    defer(() => ref.getDownloadURL().pipe(
      switchMap(url => {
        console.log('url', url);
        const saved = {
          title: diploma.title,
          description: diploma.description,
          url,
          createdAt: firebase.firestore.FieldValue.serverTimestamp(),
          createdBy: this.auth.auth.currentUser ? this.auth.auth.currentUser.uid : 'anonymous'
        };
        return this.db.doc(`diplomas/${id}`).set(saved); // you can return a Promise directly
      })
    ))
  );
}

可能的选择:

saveDiploma(diploma: { title: any; description: any; picture: any }) {
  const id = this.db.createId();
  const ref = this.storage.ref(`diplomas/${id}/original.jpg`);
  return ref.putString(diploma.picture, 'data_url').snapshotChanges().pipe(
    last(),
    switchMap(() => ref.getDownloadURL()),
    map(url => ({
      title: diploma.title,
      description: diploma.description,
      url,
      createdAt: firebase.firestore.FieldValue.serverTimestamp(),
      createdBy: this.auth.auth.currentUser ? this.auth.auth.currentUser.uid : 'anonymous'
    })),
    switchMap(saved => this.db.doc(`diplomas/${id}`).set(saved))
  );
}

这篇关于链管操作后如何以角度返回服务中的可观测对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆