Params inheritance strategy with Angular Router

Params inheritance strategy with Angular Router

Few weeks ago I discussed about Angular router, how we could make sure our data are loaded before accessing a component. If you aren’t familiar with Angular router, I suggest you have a look at my previous blog post where I introduced the router.
The example was loading data from the store (ngrx store) to check if data were loaded.
But it would have been difficult if we needed to load data from the route params. Today we will see the problem faced when taking params from the route and how it can be resolve with a newly introduced feature in Angular router since 5.2.x.

1. Getting data from the route params
2. paramsInheritanceStrategy

1. Getting data from the route params

To get data from the route params we take can use the ActivatedRouteSnapshot or the .snapshot property of the ActivatedRoute and use the .params property. Suppose that we have a route /test/:myKey, and we navigate to /test/hello, we could do the following:

const key = route.params['myKey'];
console.log(key);

// prints hello

That worked fine because the activated route was /test/:myKey which displayed the component. But if you register a child route for example /test/:myKey/test, and try to access myKey from the component, you will get undefined.

// in the router

{
    path: 'test/:myKey',
    component: MyComponent,
    children: [{
        path: 'test',
        component: MySecondComponent
    }]
}
// in my second component

const key = route.params['myKey'];

// key is undefined

The reason why myKey is undefined is that the activated route is the child route and by default params and data are localized to the route itself. Therefore myKey is only accessible from MyComponent through the params.
There are exceptions where params and data are inherited, it happens for empty routes and componentless routes.
Otherwise From a child route, it can be accessed with the .parent property which gives access to the parent route of the current route.

// in my second component

const key = route.parent.params['myKey'];

The main problem of accessing the route through the parent property is that the component becomes coupled with its position in the route hierarchy. If we change the position of the child route, for example we place it one level under, we would need to chain the code.

{
    path: 'test/:myKey',
    component: MyComponent,
    children: [{
        path: 'hello',
        component: MyHelloComponent,
        children: [{
            path: 'test',
            component: MySecondComponent
        }]
    }]
}

We will only be able to get myKey from the following:

const key = route.parent.parent.params['myKey'];

This is an issue as the route placement should be independed to the component code. Lucky us, Angular deployed a new functionality of the route available in 5.2.x onward.

2. paramsInheritanceStrategy

Since Angular 5.2.x, the router now has a new option paramsInheritanceStrategy.

RouterModule.forRoot(routes, {
    paramsInheritanceStrategy: 'always'
})

By default, the params and data are only inherited for empty route or componentless routes otherwise they are localised as we saw in 1). The problem with that is that the component code becomes coupled with the position in the route.
To allow all params and data to be passed down to the child route, we can set the paramsInheritanceStrategy to always.
By setting the inheritance strategy to always, myKey will then be available in the params regardless of the position of the component in the child components hierarchy. Not just myKey but any data or params added by parents will be concatenated together and passed down.

Only one problem is that overlapping values will be overwritten by the current activated route values.

{
    path: 'test/:myKey',
    component: MyComponent,
    data: {
        bye: "Bye"
    },
    children: [{
        path: 'hello',
        component: MyHelloComponent,
        children: [{
            path: 'test',
            component: MySecondComponent,
            data: {
                bye: "Hello"
            },
        }]
    }]
}

For example here bye value in MyHelloComponent will be Bye while in MySecondComponent, it will be Hello. It is overwritten by the current activated route.

Conclusion

Params and data in Angular Router are very important to initialize a component based on the route access by the user. Few days ago Angular released a new feature of the router called paramsInheritanceStrategy. Params inheritance strategy can be used to allow inheritance of all params and data for child routes. In this post we drafted the problem and saw how paramsInheritanceStrategy is used to solve the problem of accessing params and data from child route components. Hope you like this post, see you next time!

Comments

  1. Excellent description. You just solved one heck of an issue. A million thanks.

    ReplyDelete

Post a Comment

Popular posts from this blog

A complete SignalR with ASP Net Core example with WSS, Authentication, Nginx

Microsoft Orleans logs warnings and errors

One way to structure Web App built in F# and WebSharper