Sid*_*era 5 observable rxjs angular rxjs6
我有一个看起来像这样的表单:
该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$);
});
}
Run Code Online (Sandbox Code Playgroud)
this.fileService.upload只是一种方法,它返回一个Observable<string>基本上包装上传文件的下载URL.
this.utils.range只是一种根据长度返回数字数组的方法.所以如果长度是4,那么它将返回[0, 1, 2, 3]
我想创建一个Observable我可以订阅的,获取一个具有如下结构的Object:
{
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;
}
Run Code Online (Sandbox Code Playgroud)
我可以这样使用forkJoin:
forkJoin(...videoUrls$, featureImageUrl$)
.subscribe(downloadUrls => {
console.log(downloadUrls);
});
Run Code Online (Sandbox Code Playgroud)
然后根据长度提取视频下载URL videoUrls$,然后相应地创建我的对象.但我正在寻找一种更清洁的方法.
我也试过使用Observable.create但是不能用这个特定的用例包围我的头.
根据Buggy的建议,我也试过这个:
forkJoin(forkJoin(videoUrls$), featureImageUrl$)
.pipe(
map(([videoUrls, featureImageUrl]) => ({videoUrls, featureImageUrl}))
);
Run Code Online (Sandbox Code Playgroud)
如果选择了特征图像和视频,它的工作原理非常好.但如果我只是选择功能图像而不选择任何视频,则订阅永远不会到达.
这是一个Sample StackBlitz供您参考.
补充Buggy建议的方法
目前您的方法存在 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)
}
Run Code Online (Sandbox Code Playgroud)
你可以看到它在这场闪电战中发挥作用