Angular 2 router event listener
Solution 1
new router
constructor(router:Router) {
router.events.subscribe(event:Event => {
if(event instanceof NavigationStart) {
}
// NavigationEnd
// NavigationCancel
// NavigationError
// RoutesRecognized
});
}
old
Inject the Router and subscribe to route change events
import {Router} from 'angular2/router';
class MyComponent {
constructor(router:Router) {
router.subscribe(...)
}
}
NOTE
For the new router, don't forget to import NavigationStart
from router
module
import { Router, NavigationStart } from '@angular/router';
because if you don't import it instanceof
will not work and an error NavigationStart is not defined
will rise.
See also
- https://angular.io/docs/ts/latest/api/router/index/Router-class.html
- How to detect a route change in Angular 2?
Solution 2
You can also filter events with filter()
.
But don't just use filter(e => e is NavigationEnd)
A much better solution is to add a 'type guard' to filter()
like this:
filter((e): e is NavigationEnd => e instanceof NavigationEnd),
It contains two things:
-
e is NavigationEnd
this is the assertion you're defining a function for (this is typescript syntax and is completely stripped out of the transpiled javascript) -
e instanceof NavigationEnd
this is the actual runtime code that checks the type
The nice thing with this is that operators further down 'the pipe', like map
below now know the type is NavigationEnd
, but without the type-guard you'd have a type Event
.
If you only need to check for one event type then this is the cleanest way to do so. This also appears to be necessary in strict mode to avoid compiler errors.
Solution 3
You can use instanceof
as @GünterZöchbauer answered
this.router.events.subscribe(event => {
if(event instanceof NavigationStart) {
// do something...
}
}
or you can use a lazier approach, but remember constructor name can be changed easily while the function is still working!
this.router.events.subscribe(event => {
if(event.constructor.name === "NavigationStart") {
// do something...
}
});
Solution 4
Straight from the docs
import {Event, RouterEvent, Router, NavigationEnd} from '@angular/router';
this.router.events.pipe(
filter((e: any): e is RouterEvent => e instanceof RouterEvent)
).subscribe((evt: RouterEvent) => {
if (evt instanceof NavigationEnd) {
console.log(evt.url)
}
})
Although the docs give the code filter((e: Event)
but I changed this to filter((e: any)
or you get linting errors in WebStorm.
Solution 5
import { Router,NavigationEnd } from '@angular/router';
constructor(private route:Router){
this.routeEvent(this.route);
}
routeEvent(router: Router){
router.events.subscribe(e => {
if(e instanceof NavigationEnd){
console.log(e)
}
});
}
Yegor
Updated on July 05, 2022Comments
-
Yegor almost 2 years
How to listen state change in Angular 2 router?
In Angular 1.x I used this event:
$rootScope.$on('$stateChangeStart', function(event,toState,toParams,fromState,fromParams, options){ ... })
So, if I use this eventlistener in Angular 2:
window.addEventListener("hashchange", () => {return console.log('ok')}, false);
it isn't return 'ok', then change state from JS, only then browser history.back() function run.
Use router.subscribe() function as the service:
import {Injectable} from 'angular2/core'; import {Router} from 'angular2/router'; @Injectable() export class SubscribeService { constructor (private _router: Router) { this._router.subscribe(val => { console.info(val, '<-- subscribe func'); }) } }
Inject service in component which init in routing:
import {Component} from 'angular2/core'; import {Router} from 'angular2/router'; @Component({ selector: 'main', templateUrl: '../templates/main.html', providers: [SubscribeService] }) export class MainComponent { constructor (private subscribeService: SubscribeService) {} }
I inject this service in other components such as in this example. Then I change state, console.info() in service not working.
What I do wrong?
-
Yegor about 8 yearsDo I need run
router.subscribe(...)
in every class or I can run them onetime? In docs I don't understand what params I must enter in subscribe function? Can you write full example, please? -
Günter Zöchbauer about 8 yearsYou can do it once in a global service and then inject the service wherever you want to get access.
-
Yegor about 8 yearsIf I inject it as service in other components it doesn't return any data
-
Günter Zöchbauer about 8 yearsCan you please edit your question and add the code that demonstrates what you try to accomplish? I don't know where you inject the service to or how you do it.
-
Günter Zöchbauer about 8 yearsInstead of on the component (
providers: [SubscribeService]
) addSubscribeService
only tobootstrap(AppComponent, [OtherProviders, SubscribeService])
and nowhere else. -
Yegor about 8 yearsUnfortunately, it's not working(( Bootstrap code:
other imports... import {SubscribeService} from './services/router.subscribe'; bootstrap(GlobalAppComponent, [ROUTER_PROVIDERS, provide(LocationStrategy, {useClass: HashLocationStrategy}), HTTP_PROVIDERS, SubscribeService]);
-
Vassilis Pits over 7 yearsIt seems that this runs multiple times. @GünterZöchbauer it worked for you?
-
Günter Zöchbauer over 7 years
subscribe()
means to get notified about every event therefore the callback passed tosubscribe(...)
is called every time an event is emitted.. One navigation can emit every event listed in my code. You might want to use thefilter()
operator to filter only a specific kind of event of just useif(...)
as I did in my answer. -
David Walschots about 7 yearsWhat are your considerations for not wanting to use
instanceof
? -
Zak Henry almost 7 yearsThis approach is also brittle to minification as the constructor name could be changed, eg
event.constructor.name
might be'A'
-
Lazar Ljubenović over 6 years@GünterZöchbauer I think Angular is mature enough to remove the way it was done pre-2.0.0 version (not 2.x, 4.x, 5.x differences). Both here and on any other answer I come across. Would you agree that it's good to edit the answer(s)?
-
Günter Zöchbauer over 6 years@LazarLjubenović people often find old examples and then run into issues because the code doesn't work anymore. I think for them it's helpful to see that this is because Angular changed and that exmple is for an older Angular version. There is no other way to learn that, because old docs aren't available anymore.
-
Bryan Rayner over 5 yearsThis is a very unsafe method and should be heavily discouraged.
-
Shy Agam over 3 yearsWell said. Improved my answer. Thank you.