如何在链接管道操作后以角度从服务中返回可观察对象 [英] How to return an observable from service in angular after chaining pipe operations
问题描述
我正在尝试链接/管道操作并从使用 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屋!