Angular|RxJS - Type-ahead 搜索请求被浏览器取消(点击)

Angular|RxJS - Type-ahead search request gets cancelled by browser (on click)

我是 RxJS(和前端)的新手,但我知道以下代码中的 switchMap() 用于在用户输入文本框时中断和重新 运行 搜索请求.搜索工作正常,唯一的问题是如果用户在输入文本和在请求完成之前,浏览器完全取消了搜索请求。

(注:如果用户在处理请求的过程中不断输入,则搜索请求被取消并重新运行正确。只有点击事件会导致完全取消请求,而不会重新运行)

  search = (input: Observable<string>) => {
    return input.pipe(
      debounceTime(500),
      distinctUntilChanged(),
      switchMap((text) => text.length < 2 ? this.clearDropDown() // clear dropdown showing list of item names.
        : this.onKeyUp(text).pipe(
          map(result => {
           this.spinnerService.end(); // stop loading spinner.
          if (results.data) {
              return results.data; // return list of item names for the dropdown.
          }
      })
        )));
  }

  onKeyUp(text: string): Observable<any> {
      this.spinnerService.start(); // start loading spinner animation overlay on the page.
      return this.http.post(this.apiUrlString, { 'itemName': text }); // this search request works fine.
  }

HTML,万一是相关的:

    <div>
      <input
        id="itemSearchValue"
        type="text"
        class="form-control/bg-light/rounded/dropdown-toggle"
        [(ngModel)]="selectedItem"
        (selectItem)="onSelectItem($event)" // irrelevant to the question.
        formControlName="itemSearchValue"
        [ngbTypeahead]="search"
        #instance="ngbTypeahead" />
    </div>

当用户在某处发出点击时,如何确保请求不会被浏览器取消?我想保留 switchMap() 方法。

似乎所有订阅都被取消了onBlur

来自github:https://github.com/ng-bootstrap/ng-bootstrap/blob/master/src/typeahead/typeahead.ts

  handleBlur() {
    this._resubscribeTypeahead.next(null);
    this._onTouched();
  }

所以解决方案是不让 type-ahead 访问网络请求订阅。只需在组件内订阅并传递对数据的引用即可。

  data: string[] = [];
  sub = new Subscription();

  search = (input: Observable<string>) => {
    return input.pipe(
      debounceTime(500), // half second buffer before request starts
      distinctUntilChanged(),
      switchMap((text) => {
        if (text.length < 2) {
          this.clearDropDown(); // clear dropdown showing list of item names.
          return [];
        }
        this.subscribeToKeyUp(text); // update data
        return [this.data];
      })
    );
  };

  subscribeToKeyUp(text: string) {
    this.sub.unsubscribe(); // cancel if a request is still going
    this.spinnerService.start(); // start loading spinner animation overlay on the page.
    this.sub = this.onKeyUp(text).subscribe((results) => {
      if (results?.data) this.data = results.data;
      this.spinnerService.end(); // stop loading spinner.
    });
  }

  onKeyUp(text: string): Observable<any> {
    return this.http.post(this.apiUrlString, { itemName: text });
  }

这是一个模拟请求和响应之间 3 秒延迟的 stackblitz。在半秒去抖时间和 3 秒响应之间单击关闭仍然允许请求完成。

https://stackblitz.com/edit/angular-cgyadh?file=src/app/typeahead-basic.ts

P.S. 我看到你提到请求可能需要 30 多秒,在那种情况下我会制作一个按钮来调用 subscribeToKeyUp(text) 和从 search 函数中删除该调用。这样就不会在每封信上都触发大量请求。无论如何只是一个建议。