Nx: Error: TypeError: Cannot read property 'routeConfig' of undefined

Created on 9 Jan 2018  路  13Comments  路  Source: nrwl/nx

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());
      }
    }
  );

screen shot 2018-01-08 at 11 05 35 pm

repro needed bug

Most helpful comment

DataPersistence, Custom Router Serializers, and NgRx should all play nice.

All 13 comments

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.

  • When issuing the idiomatic CustomSerializer with @ngrx/router-store (default custom setup)
  • When providing the storeFreeze metaReducer via ngrx-store-freeze

Issue 1 - CustomSerializer setup for @ngrx/router-store

@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 root in the serialization, the DevTools seemed to be OK with it, still playing around with it. This still is an issue with StoreDevtoolsModule, as @j-walker23 pointed out.

Issue 2 - storeFreeze metaReducer

It appears that DataPersistence.navigation does not play nice with the metaReducer storeFreeze from ngrx-store-freeze.

Summary

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: 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 See workaround below.

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.

Workaround: DataPersistence.navigation + router-state + DevTools

By providing a replacer for StoreDevtoolsModule serialization, I'm able to use all these together as advertised:

  • DataPersistence.navigation
  • @ngrx/router-store
  • @ngrx/store-devtools

See 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

Was this page helpful?
0 / 5 - 0 ratings