Get a reference to a component of current route in Angular 2's router?
In fact, you don't have access to the component instance associated to the current route with your expression. You only get the component type. That's why you need to use the prototype but you get a reference to function and don't reference to methods of the component instance.
The main consequence will be that the this
keyword (if used within the methods) will be undefined.
To access the component instance associated to the current route, you could leverage the OnActivate
hook interface to set this instance into a shared service when the route is activated:
@Component({
selector: 'some-cmp',
template: `
<div>routerOnActivate: {{log}}</div>
`})
export class SomeCmp implements OnActivate {
constructor(private service:RouteStateService) {
}
routerOnActivate(next: ComponentInstruction, prev: ComponentInstruction) {
this.service.setCurrentRouteComponent(this);
}
}
Then you would be able to access the component instance this way:
var component = this.service.getCurrentRouteComponent();
It is possible to access the component instance using RouterOutletMap
that is a kind of stateful service used by Angular to store instances rendered by router-outlet
directive. You might need these types:
import { Router, RouterOutletMap, RouterOutlet } from '@angular/router';
Top-level outletMap
is a property of the router
, but it's not visible in TS so you might need cast to any
:
constructor(private router:Router) {
const rootOutletMap:RouterOutletMap = (<any>this.router).outletMap;
}
The RouterOutletMap
is a javascript object that has a property _outlets
. This _outlets
is a hash-map-object containing RouterOutlet
instances by the outlet name. If an outlet has no name, it will be 'primary'. After you got RouterOutlet
you can grab the component instance:
const rootOutletMap:RouterOutletMap = (<any>this.router).outletMap,
outletsHash = (<any>rootOutletMap)._outlets,
primaryOutlet:RouteOutlet = outletsHash['primary'], // 'primary' is the default name
component = primaryOutlet.component; // <-- this is the instance
RouterOutletMap
is a tree, so the root map has a reference to children and so on. You can organize a lookup procedure to find a component for a particular route if you need to. Here is an example of recursive components extraction:
// returns an array of all the router-outlets component currently rendered
private getComponentsChain(routerOutletMap: RouterOutletMap) {
const outlets: any = (<any>routerOutletMap)._outlets,
outletsList = [],
components = [];
_.forOwn(outlets, (value: RouterOutlet, key: string) => {
outletsList.push(value);
components.push(value.component);
});
const recursiveComponents = _.flatMap(
outletsList,
(o: RouterOutlet) => this.getComponentsChain(o.outletMap));
return [...components, ...recursiveComponents];
}
/* ...then somewhere in component: */
console.log(this.getComponentsChain((<any>this.router).outletMap));
Few points to note if you go this way:
- it uses non-public angular features so that might change in the future;
- router outlets have it's own lyfecycle, you might get 'Outlet is not activated' error if you pick it at the wrong moment.