angular - 组合一个 Observable和一个数组> 变成单个 Observable<{string, string[]}>
问题描述
我有一个看起来像这样的表格:
Program Name
和Description
是响应式表单的一部分。和Feature Image
是Video(s)
文件输入。
我有两个提交表单的按钮,另存为草稿和发布。如果所有字段都已填写,包括文件输入,则发布将被启用。另存为草稿始终启用并将提交表单。
在提交表单时: 我检查是否有特征图像。如果有,我会将其上传到 Firebase 存储桶。我对视频应用相同的检查。如果有视频,我会一一上传到 Firebase 存储桶。这是相同的代码:
let featureImageUrl$: Observable<string>;
const videoUrls$: Observable<string>[] = [];
// Check if featureImageToUpload was uploaded
if (this.featureImageToUpload) {
featureImageUrl$ = this.fileService.upload(`content/programs/images/${this.utils.generateRandomString()}`, this.featureImageToUpload);
}
// Check if video(s) was/were uploaded
if (this.videosToUpload) {
this.utils.range(this.videosToUpload.length).forEach(fileIndex => {
// tslint:disable-next-line:max-line-length
const videoUrl$ = this.fileService.upload(`content/programs/videos/${this.utils.generateRandomString()}`, this.videosToUpload[fileIndex]);
videoUrls$.push(videoUrl$);
});
}
this.fileService.upload
只是一种方法,它返回一个Observable<string>
基本上包装了已上传文件的下载 URL 的方法。
this.utils.range
只是一种根据长度返回数字数组的方法。所以如果长度是4,那么它将返回[0, 1, 2, 3]
问题:
我想创建一个Observable
可以订阅的对象,以获取具有如下结构的对象:
{
featureImageUrl: 'DOWNLOAD URL FOR THE FEATURE IMAGE' || null // null in case the file wasn't uploaded;
videos: [
'DOWNLOAD URL FOR VIDEO 1',
'DOWNLOAD URL FOR VIDEO 2',
'DOWNLOAD URL FOR VIDEO 3',
'DOWNLOAD URL FOR VIDEO 4',
...
] || null // null in case the video(s) were not uploaded;
}
到目前为止我尝试过的事情:
我可以这样使用forkJoin
:
forkJoin(...videoUrls$, featureImageUrl$)
.subscribe(downloadUrls => {
console.log(downloadUrls);
});
然后根据长度提取视频下载网址videoUrls$
,然后相应地创建我的对象。但我正在寻找一种更清洁的方式来做到这一点。
对于这个特定的用例,我也尝试过使用Observable.create
,但无法理解它。
根据Buggy的建议,我也尝试了这个:
forkJoin(forkJoin(videoUrls$), featureImageUrl$)
.pipe(
map(([videoUrls, featureImageUrl]) => ({videoUrls, featureImageUrl}))
);
如果同时选择了特征图像和视频,它工作得非常好。但是,如果我只选择特色图片而不选择任何视频,则订阅永远不会到达。
这是一个示例 StackBlitz供您参考。
解决方案
您的方法目前存在 2 个问题
您没有
featureImageUrl$
使用默认Observable
值初始化 。当forkJoin
接收到一个不可观察的值作为其参数之一时(在这种情况下undefined
),它将引发异常。当没有选择视频时,您将一个空列表传递给内部
forkJoin
. 由于forkJoin
不知道如何处理一个空的流列表,它永远不会发出值。
例如,解决方案如下:
let featureImageUrl$: Observable<string> = of(null);
let videoUrls$: Observable<string[]> = of(null);
if (this.featureImageToUpload) {
featureImageUrl$ = this.fileToStream(this.featureImageToUpload);
}
if (this.videosToUpload) {
videoUrls$ = forkJoin(Array.from(this.videosToUpload)
.map(file => this.fileToStream(file)));
}
forkJoin(videoUrls$, featureImageUrl$)
.pipe(
map(([videoUrls, featureImageUrl]) => ({ videoUrls, featureImageUrl }))
)
.subscribe(data => {
console.log({data});
});
....
private fileToStream(file: File): Observable<string> {
return this.fileService
.upload(`content/programs/videos/${this.utils.generateRandomString()}`, file)
}
你可以看到它在这次闪电战中发挥作用
推荐阅读
- android - android webview 显示错误“无法加载应用程序。此应用程序不安全”
- python - 解析 Beautiful Soup 上具有相同类的所有元素
- elasticsearch - Elasticsearch - 没有第二次重新索引的零停机时间重新索引?
- python - 标签文本下的Python抓取?
- python - 单击图像 1 次,获取位置并销毁窗口 OpenCv
- ios - iOS 13 - UIApplicationDelegate 中的 applicationWillTerminate 等效于 UISceneDelegate?
- python - 每个键将几乎相同的字典值列表组合在一起
- python - 无法生成任何 Kafka 消息
- powershell - 运行 Remote PS 脚本以部署软件
- java - 粘贴文本后编辑文本工作很奇怪