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