BeetleJuice BeetleJuice - 3 months ago 22
TypeScript Question

Angular 2: How to pass route parameters to subroute?

Using Angular 2 rc.1 and TypeScript. I'm having a lot of trouble passing routing parameters to my component when the component is loaded in a subroute. I use the

@angular/router-deprecated
package.

In my root component, I configured the routes as such:

@RouteConfig([
{path:'/top', name:'Top', component: EndPointComponent},
{path:'/sub/...', name:'Sub', component: MiddleManComponent}
])


Here is the endpoint component where I attempt to read the parameters

import {Component} from '@angular/core';
import {RouteParams} from '@angular/router-deprecated';
@Component({
template: 'Route Params: {{routeParams.params | json}}'
})
export class EndPointComponent{
constructor(private routeParams:RouteParams){}
}


Here is the middleman component with the subroute to EndPointComponent

import {Component} from '@angular/core';
import {RouteConfig, ROUTER_DIRECTIVES} from '@angular/router-deprecated';
import {EndPointComponent} from "./endpoint.component";

@Component({
directives: [ROUTER_DIRECTIVES]
template: `<router-outlet></router-outlet>`
})
@RouteConfig([
{path: '/end', name: 'End', component: EndPointComponent, useAsDefault: true}
])
export class MiddleManComponent {}


The parameters can be successfully read from the
routeParams
object of
EndPointComponent
when the component is loaded from the top-level route (eg: the route named 'Top' in the root component). However, the parameters are always empty when I navigate to
EndPointComponent
by going throug
MiddleManComponent
(eg: via the route named 'Sub' in the root component).

Do children routers scrub the parameters from parents before resolving the routes? That doesn't make much sense so I bet I'm missing something. My question is simply: how do I pass route parameters to a subroute?

PS: I tried to build a plunker to demo this setup but I gave up when I couldn't figure out why the application doesn't load.

Answer

Child routes actually get their own instance of RouteParams, distinct from the parent route's. This is done to avoid naming collisions and facilitate encapsulation of the routed component.

One way you can share a parent route's parameters with a component loaded by a child route is through a service.

@Injectable()
export class RouteParamService {
  constructor(private routeParams: RouteParams) {}

  get params() {
    return this.routeParams.params;
  }
}

@Component({
    template: 'Route Params: {{routeParams.params | json}}'
})
export class EndPointComponent{
    constructor(private routeParams:RouteParamService){}
}

@Component({
  directives: [ROUTER_DIRECTIVES]
  template: `<router-outlet></router-outlet>`,
  providers: [RouteParamService]
})
@RouteConfig([
  {path: '/end', name: 'End', component: EndPointComponent, useAsDefault: true}
])
class MiddleManComponent() { }

The RouteParamService will be instantiated at the same route level as the MiddleManComponent and so will get the same instance of RouteParams. When your service gets injected into your child route component, you'll be able to access the parent route params.

If you need 2 instances of EndPointComponent to load at different route tree levels, you'll need another tier of parent route, I think; i.e. a routed component that encapsulates both MiddleManComponent and EndPointComponent, between RootComponent.

RootComponent is not routed, so you won't be able to instantiate RouteParams for the RouteParamService from it. RouteParams is provided by the <router-outlet> component.