ngrx/router-store - route parameter selector returns undefined for the child route

2.4k Views Asked by At

I have this routing set up:

const SONGS_ROUTES = [
  {
    path: "songs",
    children: [
      // ...
      {
        path: "edit/:id",
        component: PerformancesComponent, // CHILD ROUTE
      },
      {
        path: "",
        component: PerformancesComponent,
      },
    ],
  },
];

const routes: Routes = [
  {
    path: "",
    component: ConcertsComponent,
    children: [
      {
        path: "edit/:friendlyUrl",
        component: ConcertEditComponent,   // PARENT route
        children: SONGS_ROUTES,
      },
    ],
  },
];

and I need to be able to get friendlyUrl with ngrx selectors in every component in the tree. So I defined it as follows:

export const routerFeatureKey = "router";

export const selectRouterState = createFeatureSelector<
  fromRouter.RouterReducerState
>(routerFeatureKey);

export const {
  selectCurrentRoute, // select the current route
  selectQueryParams, // select the current route query params
  selectQueryParam, // factory function to select a query param
  selectRouteParams, // select the current route params
  selectRouteParam, // factory function to select a route param
  selectRouteData, // select the current route data
  selectUrl, // select the current url
} = fromRouter.getSelectors(selectRouterState);

export const getSelectedConcertFriendlyUrl = selectRouteParam("friendlyUrl");

It does work at the "PARENT" level component (route). Which means when a user goes to edit/some-concert the selector returns some-concert. But for the /edit/some-concert/edit/songs/1 (in the child component) it returns undefined. And I have no idea why.

I tried both routerState: RouterState.Minimal and routerState: RouterState.Full. Same result.

What new things can I try?

2

There are 2 best solutions below

0
On BEST ANSWER

For those crawling the net for a solution to this, I found an alternative to writing a custom selector on another SO thread.

in app-routing.module.ts

@NgModule({
    imports: [RouterModule.forRoot(routes, {
        paramsInheritanceStrategy: 'always' <---- the important part
    })],
    exports: [RouterModule]
})

Original answer that solved the question: https://stackoverflow.com/a/51817329/5775417

0
On

To workaround this I created my own selector:

export const getSelectedConcertFriendlyUrl = createSelector(
  selectUrl,
  (url) => {
    const extractRegex = /\/concerts\/edit\/([a-zA-Z0-9_-]+)\/?.*/gi;
    const matches = extractRegex.exec(url);
    if (matches && matches.length > 1 && matches[1]) {
      return matches[1];
    }
    return undefined;
  }
);

It's doesn't include all edge cases for now, so I'll have improve it.

And then @brandonroberts kindly replied on Twitter that:

The selectors for router-store traverse down to the lowest active route in the tree, which is why you won't get that parameter. If you need to all the params in the tree, you need a custom selector.

So yes, you have to create your own selector.