Is there a clean way to get a reference to the component of current route?
This seems to work, but seems very hacky:
this.router.currentInstruction.
component.componentType.prototype.somePropertyOrFunction();
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:
Only short (but hacky) way I found is next (Angular 4, 6, 7, 8):
const currentComponent = (router as any).rootContexts.contexts
&& (router as any).rootContexts.contexts.get('primary')
&& (router as any).rootContexts.contexts.get('primary').outlet.component;
BEWARE: that's a HACK, may not work if you have more than one router outlet etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With