首页 > 解决方案 > 如何使用 RxJS 正确实现一次在时间范围内单击激活的操作按钮?

问题描述

我还在学习 RxJS。对于我的一个项目,我想实现这个“只保存一次”功能。

关于 RxJs 的视频中的代码片段如下:

const clickToSave$ = saveClick$.pipe(
    exhaustMap(() => http.post(saveURL, data) )
)

我有以下重写的代码,其中我尝试将代码片段实现到我现有的代码库中。

 const saveClick$ = new Observable();
    // TODO: error handling
    const clickToSave$ = saveClick$.pipe( exhaustMap(() => this.http.post(this.xmlendpointPdf, jsonType, this.httpOptions) )
      ).subscribe(
        result => {
          const docUrl = 'test';
          console.log(docUrl);        },
        error => {
          if (error['status'] === 0) {
            this.openAlertDialog('Unknown error');
          } else {
          this.openAlertDialog('The following error has appeared:' + error['statusText']);
          }
          console.log('There was an error: ', error);
        });
      }

...但它显然不起作用。我应该如何绑定到(click)= ....按钮 HTML 中的事件?回顾一下,我想要的是理论上你可以尽可能多地点击按钮,但它只会http.post在一段时间内执行一次操作(在这种情况下是调用),所以当用户通过点击向按钮发送垃圾邮件时。我怎样才能为我自己的特定用例成功实现这个代码片段(我想未来很多人也会寻找它)。

标签: javascriptangulartypescriptrxjsobservable

解决方案


如果您需要更多解释,请随时提出问题!

模板

<button (click)="bntClicked($event)">Save Button</button>
<br />
<button #btn>Save Button 2</button>

代码

export class AppComponent implements OnInit {
  //Solution 1 - Not a big fan of this one personally but it does work
  //Manually make sure a subscription finishes before allowing a new one
  activeSubscription: Subscription;
  bntClicked($event) {
    if (!this.activeSubscription) {
      this.activeSubscription = this.saveMock().subscribe({
        next: result => {
          console.log(result);
          this.resetSubscription();
        }
      });
    }
  }

  resetSubscription() {
    this.activeSubscription.unsubscribe();
    this.activeSubscription = undefined;
  }
  //End solution 1;

  //Solution 2 - I prefer this one

  //We get a reference to the button using ViewChild
  @ViewChild("btn", { static: true }) button: ElementRef;

  ngOnInit(): void {
    //Option 1
    fromEvent(this.button.nativeElement, "click")
      .pipe(
        //Cancel previous observable and subscribe to new/last one
        switchMap($event => this.saveMock())
      )
      .subscribe({
        next: result => console.log("switchMap", result)
      });

    //Option 2
    fromEvent(this.button.nativeElement, "click")
      .pipe(
        debounceTime(1000),
        mergeMap($event => this.saveMock())
      )
      .subscribe({
        next: result => console.log("debounceTime", result)
      });
  }
  //End solution 2;

  saveMock(): Observable<any> {
    return of({ description: "Hello World!" }).pipe(delay(1000));
  }
}

资源

StackBlitz 示例

switchMap - 学习 rjxs

debounceTime - 学习 rxjs

fromEvent - rxjs


推荐阅读