3

I have some parameters that I need to put to some of my pages, which means when these pages are visited, I want to check if they are in ngrx store or not, and use them if they are. One more rule for this is that if they exist in URL, use them and replace the ones in ngrx store.

So the order is like:

  1. use the ones from URL if there's any
  2. use the ones from ngrx store if there's any
  3. mark them as empty if there's none

I found it's easy to implement with just type script, but I don't know what should I pass as paramters with <a> element and routerLink.

Is there a way to say when RouterActions.Go is called, check if there are some parameters already in ngrx store?

david30xie
  • 946
  • 3
  • 12
  • 23

1 Answers1

2

Sure there is an easy way. Just make an effects proxy for handling routing actions and use the router just like any other NGRX-effects:

@Injectable()
export class RouterEffects {
  @Effect({ dispatch: false })
  navigate$ = this.actions$.ofType(RouterActions.GO)
    .map((action: RouterActions.Go) => action.payload)
    .do((routerPayload: RouterPayload) => {
      this.router.navigate(routerPayload.path, routerPayload.query);
  });

  @Effect({ dispatch: false })
  navigateBack$ = this.actions$.ofType(RouterActions.BACK)
    .do(() => this.location.back());

  @Effect({ dispatch: false })
  navigateForward$ = this.actions$.ofType(RouterActions.FORWARD)
    .do(() => this.location.forward());

  constructor(
    private actions$: Actions,
    private router: Router,
    private location: Location
  ) {}
}

with the router.actions.ts:

export const GO = '[Router] Go';
export const BACK = '[Router] Back';
export const FORWARD = '[Router] Forward';

export interface RouterPayload {
  path: string[];
  query?: NavigationExtras;
}

export class Go implements Action {
  readonly type = GO;
  constructor(public payload: RouterPayload) {}
}

export class Back implements Action {
  readonly type = BACK;
}

export class Forward implements Action {
  readonly type = FORWARD;
}

export type Actions
  = Go
  | Back
  | Forward;

and in your component you dispatch router actions on navigation instead of calling routerLink directly in the template:

navigate(routerPayload: RouterPayload) {
  this.store.dispatch(new RouterActions.Go(routerPayload));
}

This way you can also easily go back and forth in your routes.

Phil
  • 7,065
  • 8
  • 49
  • 91
  • "and in your component you dispatch router actions on navigation instead of calling routerLink directly in the template" Does this mean that whenever I need to navigate to some page, I need to put `click()` method to `` and call `navigate()` inside this click method? – david30xie Apr 30 '18 at 16:26
  • That's how we do it at least. In our app we delegate routing (and all other) actions to the container component of a module and let it dispatch them to be handled by redux somewhere in a black box outside that module. – Phil Apr 30 '18 at 16:32
  • Might seem too much, but if you re integrating NGRX already, I guess your app is complicated and this helps decoupling dependencies (eg only the container component should communicate with the outside world) – Phil Apr 30 '18 at 16:34
  • 1
    then when user move their cursor to the link and they won't see a desired url with full parameters, or I can generate this link inside component, which makes me think this is so complicated.... – david30xie Apr 30 '18 at 16:46