5

I've been looking throu the ngrx example-app and trying to expand it with the following:

  • when searching for the book the query is written in the url as query parameters like so http://localhost:4200/book/find?query=book_title
  • when opening the page with an url that containes a query parameter the search input box should be filled and the search displayed

What would be the right way to do such a thing ?

I have added my solution, it does the job but i'm not sure if it is any good. In it i am storing the query parameter in two places which seem like an antipattern

My solution:

in the app/books/effects/books.ts added a router navigation in the search effect, so that whenever a search is triggered the url will be updated with the query string

search$: Observable<Action> = this.actions$.pipe(
  ofType<Search>(BookActionTypes.Search),
  debounceTime(this.debounce || 300, this.scheduler || async),
  map(action => action.payload),
  switchMap(query => {
    if (query === '') {
      return empty();
    }

    const nextSearch$ = this.actions$.pipe(
      ofType(BookActionTypes.Search),
      skip(1)
    );

    return this.googleBooks.searchBooks(query).pipe(
      takeUntil(nextSearch$),
      map((books: Book[]) => {
// added //
        this.router.navigate([], {
          queryParams: { query: query },
          queryParamsHandling: 'merge',
        });
///////////
        return new SearchComplete(books);
      }),
      catchError(err => of(new SearchError(err)))
    );
  })
);

in app/reducers/index.ts added the selector for router query parameters:

export const getRouterState = createFeatureSelector<
  fromRouter.RouterReducerState<RouterStateUrl>
>('router');

export const getQueryParams = createSelector(
  getRouterState,
  state => state.state.queryParams
);

in app/books/containers/find-book-page.ts added the method

urlQuery() {
// dispatch a search action if there is a query string in url
  this.store
    .pipe(select(fromRoot.getQueryParams), take(1))
    .subscribe(queryParams => {
      if (queryParams.query) {
        this.search(queryParams.query);
      }
    });
}

this method is being called from the constructor in the find-book-page component, so when ever this component is loaded it will check if there is a query string in the url and if so dispatch an action with that query string

constructor(private store: Store<fromBooks.State>) {
  this.searchQuery$ = store.pipe(select(fromBooks.getSearchQuery), take(1));
  this.books$ = store.pipe(select(fromBooks.getSearchResults));
  this.loading$ = store.pipe(select(fromBooks.getSearchLoading));
  this.error$ = store.pipe(select(fromBooks.getSearchError));

  this.urlQuery();
}
Marko Čepo
  • 185
  • 13

0 Answers0