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

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

问题描述

我正在尝试链接/管道操作并从使用 angular fire 的 angular 服务返回一个 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) 之前添加一个终结或过滤器(在 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天全站免登陆