Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: TypeError: Cannot read property 'routeConfig' of undefined #191

Closed
suhasdeshpande opened this issue Jan 9, 2018 · 14 comments
Closed

Comments

@suhasdeshpande
Copy link

suhasdeshpande commented Jan 9, 2018

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

@j-walker23
Copy link

j-walker23 commented Jan 9, 2018

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.

@j-walker23
Copy link

j-walker23 commented Jan 10, 2018

@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 }
  }
}

@suhasdeshpande
Copy link
Author

Let me try that. Thanks for information. :)

@suhasdeshpande
Copy link
Author

IT works as expected. Nothing wrong with navigation. As @j-walker23 pointed out, CustomSerializer was filtering some important data. :)

@j-walker23
Copy link

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.

@ThomasBurleson
Copy link
Contributor

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

@jedsmith13
Copy link

Any updates on how this is coming? I am running into this issue now.

@perjerz
Copy link

perjerz commented Nov 13, 2018

Any update?

@FrozenPandaz
Copy link
Collaborator

Can someone provide a repro please?

I'm having trouble understanding what the issue here is. And a repo would help.

Thanks

@jsonberry
Copy link

jsonberry commented Dec 18, 2018

@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;
    },
  },
}),

@archermc
Copy link

archermc commented Mar 16, 2019

@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,
};

@brandonroberts
Copy link
Contributor

Can this issue be closed or is there something remaining that needs to be documented?

@suhasdeshpande
Copy link
Author

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

@vsavkin vsavkin closed this as completed Dec 4, 2019
@github-actions
Copy link

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

10 participants