angularngrxngrx-router-store

How to use NGRX Routers correctly?


I honestly was totally lost by the documentation, and besides I was wondering the following:

If I use the NGRX Router, will I need to use the angular's native app-rounting? If so, how do I integrate the NGRX Router with the <router-outlet>?

Could you give me a simple example of the same?


Solution

  • Angular Router and NGRX router work together. Angular Router is responsible for actual routing in the application and NGRX router is responsible for getting the information out from the Angular router, following is the simple example to use navigation without NGRX.

    @Injectable()
    export class SomeComponent {
      constructor(private router: Router) {}
      /*
      Your Component code  
      */
      onSubmit() {
        this.router.navigate(['/some-url'])
      }
    
    }
    

    Follow the NGRX Router documentation to setup the store.

    following is the way to use Angular routing with NGRX

    router.action.ts (dispatch actions from components for navigation to happen)

    import { createAction, props } from '@ngrx/store';
    import { NavigationExtras } from '@angular/router';
    
    export enum RouterActionTypes {
      Go = '[Router] Go',
      Back = '[Router] Back'
    }
    
    export const Go = createAction(RouterActionTypes.Go, props<{ payload: { path: any[]; query?: object; extras?: NavigationExtras } }>());
    
    export const Back = createAction(RouterActionTypes.Back);
    

    router.effect.ts (Effect handle the side effects, it catches the navigation action dispatch from component and does the actual routing)

    import { Location } from '@angular/common';
    import { Injectable } from '@angular/core';
    import { Router } from '@angular/router';
    import { Actions, createEffect, ofType } from '@ngrx/effects';
    import { tap, map } from 'rxjs/operators';
    import * as RouterActions from '../actions/router.actions';
    
    @Injectable()
    export class RouterEffects {
      constructor(private actions$: Actions, private router: Router, private location: Location) {}
    
      navigate$ = createEffect(
        () =>
          this.actions$.pipe(
            ofType(RouterActions.Go),
            map((action) => action.payload),
            tap(({ path, query: queryParams, extras }) => {
              this.router.navigate(path, { queryParams, ...extras });
            }),
          ),
        { dispatch: false },
      );
    
      navigateBack$ = createEffect(
        () =>
          this.actions$.pipe(
            ofType(RouterActions.Back),
            tap(() => this.location.back()),
          ),
        { dispatch: false },
      );
    }
    

    NGRX provides build in Selectors to get the routing information for example queryParams, url etc.

    for example you have to get the list of user by department and departmentId is in the query param of the URL

    https://localhost:4200/users?deparmentId=4
    

    Right way to read the query param is through selectQueryParams selector provided by NGRX library

    export const selectSelectedDepatmentId = selectQueryParam('deparmentId');
    
    export const selectUsersByDepartment = createSelector(
       selectUsers,
       selectSelectedDepatmentId,
       (users, departmentId) => users.filter(u => u.departmentId === departmentId)
    );