我有一个看起来像这样的表格:
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$
的长度提取视频下载URL,然后相应地创建我的Object。但是我正在寻找一种更清洁的方法。
我也尝试使用Observable.create
,但是在这种特定的使用情况下,我无法解决问题。
根据Buggy的建议,我还尝试了以下方法:
forkJoin(forkJoin(videoUrls$), featureImageUrl$)
.pipe(
map(([videoUrls, featureImageUrl]) => ({videoUrls, featureImageUrl}))
);
如果同时选择了特征图像和视频,则效果很好。但是,如果我只选择“功能图片”而不选择任何视频,则订阅将永远无法到达。
这里是Sample StackBlitz供您参考。
答案 0 :(得分:2)
补充Buggy
建议的方法您的方法当前有2个问题
您没有使用默认的featureImageUrl$
初始化Observable
。当forkJoin
收到一个非 observable-like 值作为其args之一(在本例中为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)
}
您可以看到它在this blitz
中工作