[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report
[ ] Feature request
[ ] Documentation issue or request
The routerState cannot be retrieved from selectors. Creating a selector for routerState leads to get an undefined value.
Here is the redux tools state init sequence, in case it's useful:

Being able to access routerState from anywhere in the store without being undefined.
We use NGRX to manage our state. We use several feature states.
Our store structure is created at different levels of our lazy loaded modules:
Core: router + auth
|___ OurApp Module (lazy loaded): layoutState
| ___ Admin Module (lazy loaded): adminState (containing the institutionState as described below)
Our app.module.ts:
imports: [
...
StoreModule.forRoot(reducers, { metaReducers }),
EffectsModule.forRoot(effects),
StoreRouterConnectingModule,
],
providers: [
...
{
provide: RouterStateSerializer,
useClass: fromStoreUtils.CustomRouterStateSerializer,
},
]
CustomSerializer:
export class CustomRouterStateSerializer
implements fromRouter.RouterStateSerializer<RouterStateUrl> {
serialize(routerState: RouterStateSnapshot): RouterStateUrl {
let route = routerState.root;
while (route.firstChild) {
route = route.firstChild;
}
const { url, root: { queryParams } } = routerState;
const { params } = route;
return { url, params, queryParams };
}
}
Our root/core reducer:
import * as fromNgrxRouter from '@ngrx/router-store';
import * as fromAuth from './auth.reducer';
export interface RouterStateUrl {
url: string;
queryParams: Params;
params: Params;
}
export interface State {
router: fromNgrxRouter.RouterReducerState<RouterStateUrl>;
auth: fromAuth.AuthState;
}
export const reducers: ActionReducerMap<State> = {
router: fromNgrxRouter.routerReducer,
auth: fromAuth.reducer,
};
export const getRouterState = createFeatureSelector<fromNgrxRouter.RouterReducerState<RouterStateUrl>>('router');
Creating any selector with routerState gets us an undefined routerState.
Exemple of a selector as we intend to use it:
export const getSelectedInstitution = createSelector(
getInstitutionsEntities,
getRouterState,
(entities, router): Institution => {
console.log(router);
return router.state && entities[router.state.params.institutionId];
}
);
We also tried to put a simple subscribe to select the router State in app.component.ts:
this.store.select(getRouterState).subscribe((router) => console.log(router));
These two selectors returns us an undefined value.
"@ngrx/effects": "5.1.0",
"@ngrx/entity": "5.1.0",
"@ngrx/router-store": "5.0.1",
"@ngrx/store": "5.1.0",
"@ngrx/store-devtools": "5.1.0",
Hello,
there's probably an issue with registration of router state. You need to use:
StoreRouterConnectingModule.forRoot({
stateKey: 'router' // name of reducer key
})
otherwise it will use routerReducer as default router state key.
Just tried to change the registration as stated in @bossqone comment. But it doesn't change anything and still returns undefined.
Can you reproduce same behaviour on stackblitz? I've tried basic app (without lazy modules) and it works - https://stackblitz.com/edit/angular-1gfui7, please feel free to modify my example to match your project/structure.
I think the issue is only when using the createFeatureSelector inside of a createSelector.
Here is a stack blitz with the error shown: https://stackblitz.com/edit/angular-kinkha
If you create a selector off of the feature selector it has state being returned as undefined.
The router key will be undefined initially because navigation hasn't happened yet. See https://stackblitz.com/edit/angular-v2aiih?file=app/app.module.ts for a working example.
Why is this closed?
Of course the router key is undefined initially. That's not the problem. In my case the call to the selector using the routerState selector happens way after nav init. At the moment of the call, the store contains a proper router State but the selector is unable to retrieve it and give us undefined.
I tried to reinstall node_modules without more success.
@blackholegalaxy I thought the reproduction provided was the issue. Provide a repro through stackblitz
@brandonroberts as stated by @BrianCerasuolo in https://github.com/ngrx/platform/issues/835#issuecomment-367099578
I think the issue is only when using the createFeatureSelector inside of a createSelector.
Here is a stack blitz with the error shown: https://stackblitz.com/edit/angular-kinkha
If you create a selector off of the feature selector it has state being returned as undefined.
Reproduction is also provided there, but I forked it and added a selector with some comments:
https://stackblitz.com/edit/ngrx-routerstate-undefined. See app.component.ts
Asking for: routerstate.state.url
Evaluates to: undefined.state.url
Hence the error: Cannot read property 'state' of undefined
After review the reproduction is indeed reflecting properly the encountered problem in our own stack
@miniplus @blackholegalaxy my response is still the same. The router state will be undefined until an initial navigation happens. If you want to guard against this, you can provide an initialState for the router state or guard against the router state being undefined in the selector.
https://stackblitz.com/edit/ngrx-routerstate-undefined-dega5w?file=app/app.module.ts
@brandonroberts hm... but if the initial state is anything other than what you added there everything breaks.
https://stackblitz.com/edit/ngrx-router-reducer-initial-state
Initial state set to SSR style to match url below everything breaks.
{
"state": {
"url": "/users/1",
"params": { "id": "1" },
"queryParams": {}
},
"navigationId": 0
}
https://ngrx-router-reducer-initial-state.stackblitz.io/users/1
With initial state below everything works as expected.
{
"state": {
"url": "/",
"params": {},
"queryParams": {}
},
"navigationId": 0
}
Is there a bug in my code or is the router-store giving back references to the same object in some cases and by doing so breaking memoized selectors?
How to give this initialState for routerStore? Since everything seems handled through the lib (we don't access the actual router store reducer). What is the proper way to override this?
For example, a good thing could be to register the current activated route as initial state. The initial route should not be the first route you navigate to. But the actual first loaded route.
I think ngrx router-store should init at load and detect the current route from Angular router. Because for example the initial state can vary. If you load the app from "root" or if you deeplink in a sub route...
@blackholegalaxy You provide initial state for router-store using the window.location.pathname to give you the current URL.
StoreModule.forRoot(reducers, {
metaReducers: [],
initialState: {
router: {
state: {
url: window.location.pathname,
params: {},
queryParams: {}
},
navigationId: 0
}
}
}),
@MattiJarvinen-BA The issue you are having when using SSR is a bug that you've already filed. I will look into it soon.
Hi @brandonroberts thanks about that. So there is now way for routerStore to initialize in sync with Angular router state?
@blackholegalaxy no, because the RouterState hasn't been compiled at application bootstrap. The ROUTER_NAVIGATION dispatches the routerState to the store at the earliest possible point already.
Leaving a comment in case someone ends up here - had a similar problem. The custom serializer in the original issue:
export class CustomRouterStateSerializer
implements fromRouter.RouterStateSerializer<RouterStateUrl> {
serialize(routerState: RouterStateSnapshot): RouterStateUrl {
let route = routerState.root;
while (route.firstChild) {
route = route.firstChild;
}
const { url, root: { queryParams } } = routerState;
const { params } = route;
return { url, params, queryParams };
}
}
doesn't expose a root property on the result, and the selectors need that/assume that. Just replacing the custom serializer with the minimal made it go away for me.
I fixed the issue by passing the router options with initialNavigation: 'enabled'
Most helpful comment
@brandonroberts as stated by @BrianCerasuolo in https://github.com/ngrx/platform/issues/835#issuecomment-367099578
Reproduction is also provided there, but I forked it and added a selector with some comments:
https://stackblitz.com/edit/ngrx-routerstate-undefined. See app.component.ts
Asking for:
routerstate.state.urlEvaluates to:
undefined.state.urlHence the error:
Cannot read property 'state' of undefined