代码之家  ›  专栏  ›  技术社区  ›  J King

rxjs使用combineLatest过滤数据流-流数据在不应该为空时为空

  •  0
  • J King  · 技术社区  · 2 年前

    我正在使用角度组件中的最新组合将数据流与过滤器文本输入组合在一起:

    export class RecordSearchComponent implements OnDestroy {
      @Input() gridData: Observable<TrainingRecord[]> = of([]);
    
      private filterSubject = new BehaviorSubject<string>('');
      private readonly debounceTimeMs = 300;
    
      private filterInput$ = this.filterSubject.pipe(
        debounceTime(this.debounceTimeMs),
        distinctUntilChanged(),
      )
    
      filteredData$ = combineLatest([this.filterInput$, this.gridData]).pipe(
        tap(([filter, data]) => console.log(filter, data)),
        switchMap(([filter, data]) => {
          if (filter === '' || filter === null) {
            return of(data);
          }
          const filterDescriptor = {
            field: 'nameFull',
            operator: 'contains',
            value: filter,
            ignoreCase: true,
          };
          return of(filterBy(data, filterDescriptor));
        })
      );
    
      ngOnDestroy(): void {
        this.filterSubject.complete();
      }
    
      onFilter() {
        this.filterSubject.next(this.inputText);
      }
    }
    

    filterSubject正在工作,我可以在控制台中看到结果。

    这个问题 combineLatest中的“gridData”值始终为空。但是,如果我在模板中单独订阅gridData,我可以确认数据即将到来。(gridData|async)返回所有记录。

    1 回复  |  直到 2 年前
        1
  •  1
  •   Naren Murali    2 年前

    我认为,如果我们使用@Input进行这样的初始化,您可能无法在初始化时获得值,为了安全起见,您可以在 ngOnInit .

    另外请注意:当组件初始化时,gridData应该有一个值,只有这样它才能工作!

    export class RecordSearchComponent implements OnDestroy {
      @Input() gridData: Observable<TrainingRecord[]> = of([]);
    
      private filterSubject = new BehaviorSubject<string>('');
      private readonly debounceTimeMs = 300;
      filteredData$!: Observable<TrainingRecord[]> = of([]);
    
      private filterInput$ = this.filterSubject.pipe(
        debounceTime(this.debounceTimeMs),
        distinctUntilChanged(),
      )
    
      ngOnInit() {
        this.filteredData$ = combineLatest([this.filterInput$, this.gridData]).pipe(
            tap(([filter, data]) => console.log(filter, data)),
            switchMap(([filter, data]) => {
              if (filter === '' || filter === null) {
                return of(data);
              }
              const filterDescriptor = {
                field: 'nameFull',
                operator: 'contains',
                value: filter,
                ignoreCase: true,
              };
              return of(filterBy(data, filterDescriptor));
            })
          );
      }
    
      ngOnDestroy(): void {
        this.filterSubject.complete();
      }
    
      onFilter() {
        this.filterSubject.next(this.inputText);
      }
    }