Search code examples
angularrxjsngrxngrx-storecombinelatest

Using RxJS CombineLatest with searching or selection


In my application, I'm using NGRX and RXJS. I have a window where a user can filter order, either by typing a free form text into a textbox, or clicking an order item on the page to view the details.

I have two observables which I want to call my store and get the details by filtering either ways, but I would like to use the combineLatest function to simplify my code. The text search passes in a string to search on, while the click passes in a number id. I have this already in my code:

//Text search
 this.valueChanges = this.search.valueChanges
      .pipe(debounceTime(170), distinctUntilChanged())
      .subscribe(value => {
        this.hasValue = value.length > 0;
        this.store$.dispatch(new QueryAction({ value }));
      });

//Item click
      this.clickChanges = this.selected$.subscribe(value => {  
        let Id = value.id.toString();    
        this.store$.dispatch(new QueryAction({ value: Id }));
      });

My question is how can I simplify this code to use combineLatest since both are very similar action and the implement searching of items stored in the store to filter based on text typed in.


Solution

  • I will answer the question in two parts, you want to combine does two streams and trigger the QueryAction that should be fairly simple like

    const searchStream =  this.search.valueChanges
      .pipe(debounceTime(170), 
            distinctUntilChanged(), 
            filter(value => value.length > 0)
            );
    const clickStream = this.selected$.pipe(map(value => value.id.toString());
    merge(searchStream, clickStream)
    .pipe(tap(value => this.store$.dispatch(new QueryAction({ value: value }), 
          takeWhile(() => !destroy) // make destroy= true in ngOnDrestroy()
    ).subscribe();
    

    Notice I use merge instead of combineLatest, this is because the later will expect for both streams to produce something before it allows the action to be fired, and you will receive both values, what you want is if either the search or the click produce an event then the action should trigger which is why I use merge.

    Now I will recommend you to revise the way you are approaching this, not sure if you have read about the dumb vs smart philosophy, google it if you haven't it helps a lot when you use ngrx, check the ngrx example app https://github.com/ngrx/platform/tree/master/example-app,for me that was the best doc .
    If I understood well what you want to achieve, I will have a dumb component for the input search (this I imaging is a sort of suggestion box that autocomplete the item ) which outputs the query event when an option is selected via click or enter, and the item list page will be another dumb component that outputs a query event when click, each event will be bound to the same method in the container (smart component) which will dispatch the QueryAction Hope it helps