避免 http 请求垃圾邮件

时间:2021-06-14 14:21:29

标签: angular typescript rxjs

我有一个切换开关,可以在触发时发出 http PATCH 请求。您可以在下面看到它的样子:

enter image description here enter image description here

模板:

<div id="toggle-status-btn-container">
    <div class="slider" [ngClass]="{'to-right': !shopIsOpen}"></div>
    <div class="label-container">
        <label class="store-opened" (click)="updateShopSlotsStatus(true)" [ngClass]="{'toggled-opened-text': !shopIsOpen}">OPENED</label>
    </div>
    <div class="label-container">
        <label class="store-closed" (click)="updateShopSlotsStatus(false)" [ngClass]="{'toggled-closed-text': !shopIsOpen}">CLOSED</label>
    </div>
</div>

效果很好,但现在用户可以通过这个切换开关发送垃圾邮件,连续触发多个 http 请求。

我能做些什么来防止这种行为?如果用户向这个切换开关发送垃圾邮件,我不想触发 http 请求。也许有办法只触发最后一个?由于我对 RxJs 很陌生,我真的不知道如何解决这个问题。

这里是点击事件调用的方法,在组件.ts中:

updateShopSlotsStatus(isOpen: boolean){
    this.shopIsOpen = isOpen;
    this.apiService.updateShopSlotsStatus(isOpen, this.weekDay).subscribe();
}

还有 http 请求,在一个服务文件中:

updateShopSlotsStatus(isOpen: boolean, weekDay: string){
    const endpoint = this.url + "shipping/" + this.webzineId + "/delivery_slots" + "/";
    return this.http.patch(endpoint, {"slots": { [weekDay] : { "enabled": isOpen }}});
}

提前致谢。

1 个答案:

答案 0 :(得分:2)

您可能希望像在 this StackBlitz 中一样使用 BehaviorSubjectswitchMap 的组合。

在这里,我将打开和关闭按钮绑定到一个更改 BehaviorSubject 值的函数,如下所示:

模板:

  <button
    (click)="updateShopSlotsStatus(true)"
    [ngClass]="{'selected': shopSlotStatus$ | async}"
  >
    OPEN
  </button>
  <button
    (click)="updateShopSlotsStatus(false)"
    [ngClass]="{'selected': !(shopSlotStatus$ | async)}"
  >
    CLOSED
  </button>

ts:

  updateShopSlotsStatus(isOpen: boolean) {
    this.shopSlotStatusSubject$.next(isOpen);
  }

然后您可以像这样观察 BehaviorSubject 上的变化:

  private shopSlotStatusSubject$: BehaviorSubject<
    boolean
  > = new BehaviorSubject(false);

  // shared so only one subscription is maintained
  private readonly shopSlotStatus$ = this.shopSlotStatusSubject$
    .asObservable()
    .pipe(share());

  readonly changeSlotStatus$ = this.shopSlotStatus$.pipe(
    // you could introduce a debounceTime here if you wanted
    // debounceTime(500),
    tap(() => (this.changingStatus = true)),
    // faked API call here
    switchMap(status => this.appService.updateShopSlotsStatus(status)),
    tap(() => (this.changingStatus = false))
  );

如果源(在本例中为 switchMap observable)发出,changeSlotStatus$ 运算符将取消任何飞行中的 observable。

我在 Stackblitz 中包含了 exhaustMapmergeMap 的导入。将 switchMap 更改为这两个运算符以查看它们的工作方式有何不同。 exhaustMap 将忽略所有后续发射,直到正在进行的发射完成,而 mergeMap 将触发与按下按钮一样多的请求。我会让你来决定哪种方法最好!您可以在 learn rxjs. 了解更多信息。我建议您阅读 RxJS 和不同的运算符以及如何使用 pipe 组合它们。 RxJS 是个好东西。

如果您想在请求正在进行时禁用按下的按钮,您也可以绑定到 changingStatus 布尔值。

相关问题