多次发出RxJS http请求

时间:2020-05-25 07:00:34

标签: angular rxjs behaviorsubject rxjs-observables

我已经在我的ng-select元素上附加了一个open()方法,以便使用来自外部API的数据填充它。

我遇到的问题:如果我打开下拉菜单5次,然后键入一个字母,它将向服务器发出5个http请求,以便用数据填充它。使用虚拟滚动功能时也会出现同样的问题。

component.html

<ng-select [items]="filterValuesBuffer"
         [typeahead]="filterValuesInput$[filter.name]"
         [virtualScroll]="true"
         [multiple]="true"
         [closeOnSelect]="false"
         [loading]="filterValuesLoading[filter.name]"
         [(ngModel)]="filter.filter_values"
         (scrollToEnd)="onScrollToEnd(filter.name)"
         (open)="onFilterOpen(filter.name)"
         typeToSearchText="No values found"
         bindLabel="name">
</ng-select>

component.ts

filterValuesInput$: Map<string, Subject<string>[]> = new Map();

onFilterOpen(filterName) {
    this.filterValuesLoading[filterName] = true;

    this.getFilterValues(filterName, '')
      .subscribe(res => {
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = res.filter_values;
      });
}


getFilterValues(filterName, afterKey) {
    return this.filterValuesInput$[filterName].pipe(
      tap(() => this.filterValuesLoading[filterName] = true),
      startWith(''),
      distinctUntilChanged(),
      switchMap(term  => this.search.getFilterValues(filterName, '' + term, '' + afterKey)),
    )
}

如何防止这种行为?

编辑虚拟滚动条:

(scrollToEnd)="fetchMore(filter.name)"

fetchMore(filterName) {
    this.filterValuesLoading[filterName] = true;

    this.getFilterValues(filterName, this.afterKey)
      .subscribe(res => {
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = this.filterValuesBuffer.concat(res.filter_values);
      })
  }

2 个答案:

答案 0 :(得分:1)

那是因为您从未退订getFilterValues()。您应该绑定到(close)并在那里退订:

onFilterOpen(filterName) {
  this.subscription = this.getFilterValues(filterName, '')
    .subscribe(res => ...);
}

onFilterClose() {
  this.subscription.unsubscribe();
}

您最终可以使用takeWhile()运算符。参见Angular/RxJs When should I unsubscribe from `Subscription`

答案 1 :(得分:1)

尝试如下更改您的方法:-

public openedFiterName = {};
onFilterOpen(filterName) {
    this.filterValuesLoading[filterName] = true;
    if(this.openedFilterName[filterName]) {
      this.filterValuesLoading[filterName] = false;
      this.filterValuesBuffer = this.openedFilterName[filterName];
      return;
    }
    this.getFilterValues(filterName, '')
      .subscribe(res => {
        this.openedFiterName[filterName] = res.filter_values; 
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = res.filter_values;
      });
}

fetchMore(filterName) {
    this.filterValuesLoading[filterName] = true;

    this.getFilterValues(filterName, this.afterKey)
      .pipe(take(1)).subscribe(res => {
        this.afterKey = res.after_key;
        this.filterValuesLoading[filterName] = false;
        this.filterValuesBuffer = this.filterValuesBuffer.concat(res.filter_values);
      })
  }