检查可观察对象数组是否已以同步方式完成?

时间:2018-06-25 20:52:18

标签: angular rxjs reactive-programming

在我的应用中,如果表单中的任何数据尚未完成加载,我希望“保存”按钮不执行任何操作。我表单中的数据源都是Observablessource1$source2$

由于用户可以随时单击按钮,因此我希望能够检查是否有任何Web API请求处于挂起状态,然后它们什么也不做-否则保存。

我在想像这样的东西:

saveButton_onClicked() {
    if (// source1$ and source2$ are completed) {
        this.saveForm();
    }
}

在任何时候,可以将这些可观察变量中的任何一个分配给新的可观察变量(例如,刷新数据时),并且我认为forkJoin在这里不起作用,因为我需要知道实时 (无论是否保存表单),我都不希望click事件正在等待可观察到的forkJoin的解决。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

实际上,我认为最简单的方法是使用forkJoinfinalize运算符,而不是检查源Observable本身,而是创建一个属性。 loading,您可以随时检查并查看是否有待处理的Observable:

whatever() {
  this.loading = true;

  forkJoin(source1$, source2$)
    .pipe(
      finalize(() => this.loading = false)
    )
    .subscribe();
}

saveButton_onClicked() {
  if (!this.loading) {
    ...
  }
}

答案 1 :(得分:1)

嗯,有很多方法可以给猫皮。 有些比其他的更优雅。我希望将额外的可观察属性的数量保持最小,在这种情况下,该数量应该为2。我将添加属性isRunningRequest$,该属性的发射值是一个标志,如果当前正在运行操作,则为true。通过在另一个可观察到的asyncAction$上的聚合,可以使该标志变得生动起来,以用于跟踪当前正在运行的动作:

export class AsyncActionData {
  actionType: 'start' | 'end';
  actionToken: string;
}

    public asyncAction$ = new Subject<AsyncActionData>();

    public isRunningRequest$ = new BehaviorSubject<boolean>(false);

    constructor(...) {
        this.asyncAction$
            .pipe(
                // we keep an array of currently running actions, and add
                // or remove from the array according to the action type
                scan((arr: string[], action: AsyncActionData) => {
                    return action.actionType === 'start'
                        ? arr.concat(action.actionToken)
                        : arr.filter(action => action !== action.actionToken);
                }, []),
                map(arr => arr.length === 0 ? false : true)
            )
            .subscribe(requestsAreRunning => this.isRunningRequest$.next(requestsAreRunning));
    }

执行操作时,您会在asyncAction$上发出事件:

this.asyncAction$.next({actionType: 'start', actionToken: 'action1'});
this.http.post(...)
   .subscribe(result => ...,
              null,
              () => this.asyncAction$.next({actionType: 'end', actionToken: 'action1'})
   );

(所有代码都未经测试,但是应该是正确的)

有关scan运算符的文档,请参见herehere