有条件地链接多个可观察对象的更简洁方法

时间:2019-06-15 13:36:52

标签: angular rxjs angular2-observables

我有一种方法可以更新MySQL数据库上的“请求”。该请求可以选择包含附件,在这种情况下,我需要发出其他HTTP请求以更新或添加附件记录(到另一个DB表)并上传文件。

我有一个实用的方法来更新请求,并可以选择跳过附件HTTP请求,但是我想知道一种更简洁的方法来实现。通常,我是Angular和RXJS的新手,因此rxjs运算符的方法和使用可能不是最佳方法。

基本上,我正在寻找在订阅之前有条件地链接一些可选的可观察对象或直接跳到订阅的最佳方法。

我一直在寻找iif的潜在解决方案,返回Observable.empty()和不同的rxjs运算符,但是当我想完全跳过它们时,这些似乎是map函数中的选项。

onUpdateRequest() {
    // if there are no attachments added to the request
    if (this.attachments.length <= 0) {
        this.callUpdateRequest().subscribe(() => {
            // some page and form tidy up
        });

    // there are attachments, so process the new request and then file uploads
    } else {
        this.callUpdateRequest().pipe(
            switchMap(() => {
                return of(this.attachments);
            }),
            mergeMap(attachments => {
                return attachments.map(attachment => {
                    return attachment;
                });
            }),
            mergeMap(attachment => {
              return this.attachmentsService.addAttachmentFile(attachment)
                  .pipe(map(fileData => {
                          return fileData;
                   }));
            }),
            mergeMap(fileData => {
                return this.attachmentsService.addAttachment(
                    this.requestId, fileData.fileUrl
                ).pipe(
                    map(attachments => {
                        return attachments;
                    })
                );
            }),
            takeLast(1)
        )
        .subscribe(() => {
            // some page and form tidy up
        });
    )
}

private callUpdateRequest() {
    return this.requestsService.updateRequest(
        // all the request params
    )
}

1 个答案:

答案 0 :(得分:1)

在RxJs中,有一个有用的运算符(也是静态方法)iif(),顾名思义,它的工作方式与JS if / else相似。

使用方式

iif(
  () => state to check,
  o1,  // Observable to execute when statement is truthy
  o2   // Observable to execute when statement is falsy
)

还有一个defer(),您需要根据需要创建一个可观察的对象(否则JS会首先尝试编译一个可观察的对象,这可能会导致一些错误,因此每次使用传入的值时,我都会使用它通过观察)。

可以像

一样使用
iif(
  () => statmenet to check,
  defer(() => o1),
  defer(() => o2)
)

您的代码可以通过以下方式重写

getRequest(attachments) {
    return iif(
        () => attachments.length === 0,
        defer(() => this.callUpdateRequest()),
        defer(() => this.callUpdateRequest().pipe(
            switchMapTo(of(attachments)),
            mergeMap(attachments => {
                return attachments.map(attachment => {
                    return attachment;
                });
            }),
            mergeMap(attachment => {
              return this.attachmentsService.addAttachmentFile(attachment)
                  .pipe(map(fileData => {
                          return fileData;
                   }));
            }),
            mergeMap(fileData => {
                return this.attachmentsService.addAttachment(
                    this.requestId, fileData.fileUrl
                ).pipe(
                    map(attachments => {
                        return attachments;
                    })
                );
            }),
            takeLast(1)
        ))
    );
}

onUpdateRequest() {
   this.getRequest(this.attachments).subscribe(() => {
       // do whatever you want
   })
}

我对您的代码进行了一些划分,使其更加通用和可测试。

P.S。为什么写this.attachments.length <= 0可以小于0?