I am facing following issue on a very basic setup of ngrx store where I want to use navigation method provided by datapersistence lib. Any help would be greatly appreciated. @vsavkin This is the error I was talking about in our chat the other day. :) I am pretty sure I have made some configuration blunder. Thanks a lot for your time. This library simplifies lot of things and makes Angular super fun.
Router setup
import { RouterModule, Routes } from '@angular/router';
import * as fromComponents from './components';
export const CLIENT_ROUTES: Routes = [
{ path: '', component: fromComponents.LoginComponent },
{
path: 'dashboard',
component: fromComponents.DashboardComponent
},
{
path: 'projects/:projectName',
component: fromComponents.ProjectDetailsComponent
},
{
path: 'settings',
component: fromComponents.SettingsComponent
},
{
path: 'callback',
component: fromComponents.FetchUserProfileComponent
}
];
export const routes = RouterModule.forRoot(CLIENT_ROUTES, {
initialNavigation: 'enabled',
enableTracing: false
});
Appmodule setup
@NgModule({
imports: [
BrowserModule,
environment.production
? ServiceWorkerModule.register('/ngsw-worker.js')
: [],
FormsModule,
ReactiveFormsModule,
HttpClientModule,
NxModule.forRoot(),
CmComponentModule,
routes,
store,
EffectsModule.forRoot(effects),
!environment.production ? StoreDevtoolsModule.instrument() : [],
StoreRouterConnectingModule
],
declarations: [RootComponent],
bootstrap: [RootComponent],
providers: [
{
provide: RouterStateSerializer,
useClass: CustomSerializer
},
...effects,
...services
]
})
Effect file where I am using data-persistence.navigation
@Effect()
fetchUserData$ = this.dataPersistence.navigation(
fromComponents.FetchUserProfileComponent,
{
run: (
action: ActivatedRouteSnapshot,
state: fromCmStateInterface.ApplicationState
) => {
console.log('I was called');
return {
type: fromAction.USER_PROFILE_LOADED,
payload: {
isLoggedIn: true,
user: null
}
};
},
onError: (action, error) => {
console.error('Error###', error.toString());
}
}
);

I am also getting this error. The action emitted from ngrx/router-store does not have a root field so a.payload.routerState.root returns null breaking findSnapshot Seen here.
@suhasdeshpande I figured it out. At least i think. First, i had to remove the CustomSerializer.
After doing that my app was crashing deep inside the polyfills. But i had storeFreeze (ngrx-store-freeze) as a meta reducer. After removing that as well. The root field was in the action payload.
Edit
It seems like you can also change your serializer to something like this.
export class CustomSerializer implements RouterStateSerializer<RouterStateUrl> {
serialize(routerState: RouterStateSnapshot): RouterStateUrl {
const { url } = routerState
const { queryParams } = routerState.root
let state: ActivatedRouteSnapshot = routerState.root
while (state.firstChild) {
state = state.firstChild
}
const { params } = state
return { url, queryParams, params, root: state.root }
}
}
Let me try that. Thanks for information. :)
IT works as expected. Nothing wrong with navigation. As @j-walker23 pointed out, CustomSerializer was filtering some important data. :)
One thing to note here. StoreDevtoolsModule will now be broken if you add root to the CustomSerializer. The chrome extension falls over. So for now you have to choose between using nx.DataPersistance and the redux dev tools.
DataPersistence, Custom Router Serializers, and NgRx should all play nice.
Any updates on how this is coming? I am running into this issue now.
Any update?
Can someone provide a repro please?
I'm having trouble understanding what the issue here is. And a repo would help.
Thanks
@FrozenPandaz
Note: See workaround below 馃帀
Two different issues can arise when attempting to use DataPersistence.navigation with traditional NgRx setups.
CustomSerializer with @ngrx/router-store (default custom setup)storeFreeze metaReducer via ngrx-store-freeze@j-walker23 points out that keeping root in the serialization of the routerReducer allows for DataPersistence.navigation to work as expected, and I can confirm this as of 12/18/18.
Note: When keeping This still is an issue with root in the serialization, the DevTools seemed to be OK with it, still playing around with it.StoreDevtoolsModule, as @j-walker23 pointed out.
It appears that DataPersistence.navigation does not play nice with the metaReducer storeFreeze from ngrx-store-freeze.
Edit: _This is not a bug with DataPersistence, I think it should be properly filed under feature requests._
Neither of these issues are with DataPersistence itself, but there could be feature requests for DataPersistence.navigation to play nice with these other setups.
By following @j-walker23's instruction to keep root in my CustomSerializer, and removing storeFreeze from ngrx-store-freeze, I was able to successfully use DataPersistence.navigation.
Caveat: See workaround below.StoreDevtoolsModule does still appear to break by keeping the ActivatedRouteSnapshot as root in the serializer, which leads me to believe without further work the choice would still be (StoreDevtoolsModule + router-state + storeFreeze) vs. (DataPersistence.navigation + router-state) - unfortunately, that means for me personally that I can't justify the use of DataPersistence.navigation yet
Using StoreDevtoolsModule is an essential part of an NgRx workflow, I think if we want to enable devs to really use DataPersistence.navigation there would be some work required.
By providing a replacer for StoreDevtoolsModule serialization, I'm able to use all these together as advertised:
DataPersistence.navigation@ngrx/router-store@ngrx/store-devtoolsSee here: https://ngrx.io/guide/store-devtools/config#serialize
Here: https://github.com/zalmoxisus/redux-devtools-extension/blob/master/docs/API/Arguments.md#serialize
And here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#The_replacer_parameter
Note: no workaround for the storeFreeze metaReducer yet, but I'm not as concerned with that, code reviews should catch mutation issues 馃槃
StoreDevtoolsModule.instrument({
serialize: {
options: {
undefined: true, // same as serialilze: undefined,
},
replacer: (key, value) => {
if (value instanceof Router) {
return undefined;
}
if (
key === 'router' &&
typeof value !== 'undefined' &&
typeof value !== 'function'
) {
return {
url: value.state.url,
params: value.state.params,
queryParams: value.state.queryParams,
};
}
return value;
},
},
}),
@jsonberry First of all, thanks so much for this workaround. It's a life saver.
Just wanted to post a rather obvious fix to an issue I was having in case anyone is following this and got tripped up.
Implementing the replacer for the StoreDevtoolsModule I encountered an error as follows:
TypeError: Cannot read property 'url' of undefined
app.module.ts:122
at replacer (http://localhost:4200/main.js:41461:61)
at e (<anonymous>:1:61571)
at e (<anonymous>:1:63249)
at e (<anonymous>:1:63249)
at e (<anonymous>:1:63075)
at Object.t [as decycle] (<anonymous>:1:63281)
at Object.e.stringify (<anonymous>:1:13618)
at m (<anonymous>:1:68615)
at S (<anonymous>:1:70722)
at Function.O [as send] (<anonymous>:1:70975)
This was fixed by altering the replacer's return statement to add some null checking:
return {
url: value.state && value.state.url,
params: value.state && value.state.params,
queryParams: value.state && value.state.queryParams,
};
Can this issue be closed or is there something remaining that needs to be documented?
I have no objection on closing this. Github reminders are not very well understood by me. I always loss the issues I have opened or asked questions about. :D
Most helpful comment
DataPersistence, Custom Router Serializers, and NgRx should all play nice.