0

I am using combine latest in an angular component to bring together a stream of data with a filter text input:

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);
  }
}

The filterSubject is working and I can see the results in the console.

The problem is that the "gridData" value inside combineLatest is always empty. But I can confirm that data is coming in if I subscribe to the gridData on its own in the template. (gridData | async) returns all the records.

1 Answer 1

1

I think if we initialize like this using @Input you might not get the value on initialization, as a safety, you can initialize on ngOnInit.

Also please note: The gridData should have a value when the component is initializing only then it will work!

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);
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.