仅当单击按钮时才触发 observables 链

时间:2021-04-25 02:38:33

标签: javascript angular rxjs

我想从服务中执行 toggleButtonOnClick$() 函数,只有当我点击一个按钮时。此函数将保存当前状态,服务稍后将收到此更改并更新 usersObs$。

每当发生上述情况时,toggleButtonOnClick$ 都会再执行几次,即使我没有再次点击该按钮。

如何防止这种情况发生并使此函数仅在我对 clickSubject 执行 .next() 而不是在 userObs$ 更改时执行?

我会写一个例子来说明整个情况

按钮组件

private userClick = new Subject<null>();
private obs1$: Observable<string>();
private obs2$: Observable<string>();
private obs3$: Observable<boolean>();

ngOnInit(): void {
   this.obs2$ = this.obs1$.pipe(
      switchMap((value) => this.someService.getSomePropBasedOnValue$(value))
   );

   this.obs3$ = this.obs2$.pipe(
      switchMap((value) => this.someService.checksAndReturnsBoolean$(value))

   this.subscriptions.add(
      this.someService.toggleButtonOnClick$(this.obs2$, this.userClick).subscribe()
   )
}

ngOnDestroy(): void {
   this.subscriptions.unsuscribe();
}

onClick(): void {
   // emit a value when click on button to start observable chain
   this.userClick.next();
}

HTML

<div 
        [attr.tooltip]="(obs3$ | async) ? 
            ('text_translation_1' | transloco)
            : ('text_translation_2' | transloco)"
        >
        <span 
            *ngIf="(obs3$ | async) && !isHovering"
            >
            Something here
        </span>

        <span 
            *ngIf="(obs3$ | async) && isHovering"
            >
            Something here
        </span>

        <span 
            *ngIf="!(obs3$ | async)"
            >
            Something here
        </span>
    </div>

SomeService

    public checksAndReturnsBoolean$(id): Observable<boolean> {
        return this.userObs$.pipe(
           map((users) => { users.some(((user) => user.id === id)) }
        );
    }

    public getSomePropBasedOnValue$(id): Observable<SomeObject | null> {
        return this.userObs$.pipe(
           map((users) => { users.find(((user) => user.id === id)) ?? null }
        );
    }

    public toggleButtonOnClick$(obs2$, userClick): Observable<void> {
        return userClick.pipe(
            switchMap(() => obs3$),
            switchMap((id) => combineLatest([this.getSomeDataById$(id), of(id)]))
        ).pipe(
            map(([data, id]) => {
                // some code block that gets executed everytime an observable emits new value
            })
        );

一切完成后,我会尝试在点击后存储用户的决定。所以 userObs$ 得到更新,一旦发生这种情况,toggleButtonOnClick$ 中的块将再次执行,不是一次,而是 2 有时 3 或 4。

顺便说一句,在组件中,obs2$ 使用异步管道在 DOM 上显示/隐藏内容。也许这也是在服务可观察更改后触发调用。

我已经尝试了几件事,但都没有运气。

任何提示或帮助或指导将不胜感激。

谢谢。

1 个答案:

答案 0 :(得分:0)

我需要的是在我的服务的不同功能上使用 shareReplay(1) 和 take(1) 以使其按预期工作,而不会重复不必要的调用。

它最终看起来像这样:

public checksAndReturnsBoolean$(id): Observable<boolean> {
        return this.userObs$.pipe(
           map((users) => { users.some((user) => user.id === id) }),
           take(1)
        );
    }

    public getSomePropBasedOnValue$(id): Observable<SomeObject | null> {
        return this.userObs$.pipe(
           map((users) => { users.find((user) => user.id === id) ?? null }),
           shareReplay(1)
        );
    }