I am looking to detect a route change in my AppComponent
.
Thereafter I will check the global user token to see if the user is logged in so that I can redirect the user if the user is not logged in.
I am looking to detect a route change in my AppComponent
.
Thereafter I will check the global user token to see if the user is logged in so that I can redirect the user if the user is not logged in.
In Angular 2 you can subscribe
(Rx event) to a Router instance.
So you can do things like:
class MyClass {
constructor(private router: Router) {
router.subscribe((val) => /*whatever*/)
}
}
Since rc.1:
class MyClass {
constructor(private router: Router) {
router.changes.subscribe((val) => /*whatever*/)
}
}
Since 2.0.0:
See also : Router.events doc
class MyClass {
constructor(private router: Router) {
router.events.subscribe((val) => {
// see also
console.log(val instanceof NavigationEnd)
});
}
}
val
is empty when using the browser back and forward buttons :( –
Magel data
in this event I passed in route configuration? –
Abode event._root.children[0].value._routeConfig.data
I hope there can be better way –
Abode if (val instanceof NavigationStart)
to make it fire once –
Capful filter
operator. router.events.pipe(filter(e => e instanceof NavigationEnd).subscribe((e) => { ... }
–
Keciakeck .subscribe(
–
Parmentier router.events .pipe(filter((event): event is NavigationEnd => event instanceof NavigationEnd)) .subscribe((event: NavigationEnd) => { console.log(event.url); });
–
Brewery RxJS 6
router.events.pipe(filter(event => event instanceof NavigationStart))
Thanks to Peilonrayz (see comments below)
new router >= RC.3
import { Router, NavigationStart, NavigationEnd, NavigationError, NavigationCancel, RoutesRecognized } from '@angular/router';
constructor(router:Router) {
router.events.forEach((event) => {
if(event instanceof NavigationStart) {
}
// NavigationEnd
// NavigationCancel
// NavigationError
// RoutesRecognized
});
}
You can also filter by the given event:
import 'rxjs/add/operator/filter';
constructor(router:Router) {
router.events
.filter(event => event instanceof NavigationStart)
.subscribe((event:NavigationStart) => {
// You only receive NavigationStart events
});
}
Using the pairwise
operator to get the previous and current event also is an nice idea. https://github.com/angular/angular/issues/11268#issuecomment-244601977
import 'rxjs/add/operator/pairwise'; import { Router } from '@angular/router'; export class AppComponent { constructor(private router: Router) { this.router.events.pairwise().subscribe((event) => { console.log(event); }); }; }
Argument of type '(event: Event) => void' is not assignable to parameter of type
–
Pelpel Argument of type '(event: Event) => void' is not assignable to parameter of type
error is because in your filter snippet you are subscribing to an object of type Event instead of NavigationEvent. –
Mcmanus data
in this event I passed in route configuration? –
Abode Router
and try to get it from router.routerstate.activatedRoute...
or router.routerstate.snapshot...
Not sure if it's available there, it's quite some time I checked. –
Stephine pairwise
is being called thrice any reason @GünterZöchbauer / –
Nucleolated filter
is not related to Angular. Observable
is RXSJ5 and there still is filter
–
Stephine router.events.pipe(filter(event => event instanceof NavigationStart))
on AppRoutingModule, now its working fine. Thanks. –
Rev router.events.pipe(filter((event: Event): event is NavigationEnd => event instanceof NavigationEnd));
. See github.com/ReactiveX/rxjs/issues/3125#issuecomment-345557136 –
Benford For Angular 7 someone should write like:
this.router.events.subscribe((event: Event) => {})
A detailed example can be as follows:
import { Component } from '@angular/core';
import { Router, Event, NavigationStart, NavigationEnd, NavigationError } from '@angular/router';
@Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class AppComponent {
constructor(private router: Router) {
this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationStart) {
// Show loading indicator
}
if (event instanceof NavigationEnd) {
// Hide loading indicator
}
if (event instanceof NavigationError) {
// Hide loading indicator
// Present error to user
console.log(event.error);
}
});
}
}
this
if it refers to an @Input()
, but here, this.router
is injected in the constructor, so perfectly defined... –
Editheditha Angular 7, if you want to subscribe
to router
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
constructor(
private router: Router
) {
router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
console.log(event.url);
});
}
url
and urlAfterRedirects
, in case of a redirect the event has url
set to from which path redirection is made and urlAfterRedirects
set to path after redirect –
Proteiform Angular 4.x and above :
This can be achieved using url property of ActivatedRoute class as below,
this.activatedRoute.url.subscribe(url =>{
console.log(url);
});
Note:
That you need to import and inject the provider from angular/router
package
import { ActivatedRoute } from '@angular/router`
and
constructor(private activatedRoute : ActivatedRoute){ }
In Angular 8 you should do like this.router.events.subscribe((event: Event) => {})
Example:
import { Component } from '@angular/core';
import { Router, Event } from '@angular/router';
import { NavigationStart, NavigationError, NavigationEnd } from '@angular/router';
@Component({
selector: 'app-root',
template: `<router-outlet></router-outlet>`
})
export class AppComponent {
constructor(private router: Router) {
//Router subscriber
this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationStart) {
//do something on start activity
}
if (event instanceof NavigationError) {
// Handle error
console.error(event.error);
}
if (event instanceof NavigationEnd) {
//do something on end activity
}
});
}
}
In angular 6 and RxJS6:
import { filter, debounceTime } from 'rxjs/operators';
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
debounceTime(40000)
).subscribe(
x => {
console.log('val',x);
this.router.navigate(['/']); /*Redirect to Home*/
}
)
import {Router, NavigationEnd} from "@angular/router"
–
Lieutenant In Angular 10, you can do something like the following...
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { filter } from 'rxjs/operators';
@Component({
selector: 'app-my-class',
templateUrl: './my-class.component.html',
styleUrls: ['./my-class.component.scss']
})
export class MyClassComponent implements OnInit {
constructor(private router: Router) {}
ngOnInit(): void {
this.router.events
.pipe(filter(event => event instanceof NavigationEnd))
.subscribe((event: NavigationEnd) => {
// code goes here...
});
}
}
Router 3.0.0-beta.2 should be
this.router.events.subscribe(path => {
console.log('path = ', path);
});
The answers here are correct for router-deprecated
. For the latest version of router
:
this.router.changes.forEach(() => {
// Do whatever in here
});
or
this.router.changes.subscribe(() => {
// Do whatever in here
});
To see the difference between the two, please check out this SO question.
Edit
For the latest you must do:
this.router.events.subscribe(event: Event => {
// Handle route change
});
router
has been updated again (I haven't updated my answer yet), so I'm not sure how it is for the latest. For the router
I wrote about, you couldn't. @Symmetry –
Extension After spending some time searching a solution I have found two updated workarounds for Angular 13.1.1:
constructor(private router: Router) {
router.events.forEach((event) => {
if (event instanceof NavigationStart) {
// Your code
// Use (event.url) to get URL that is being navigated
}
});
}
routerSubscription: Subscription | undefined;
constructor(private router: Router) {}
ngAfterViewInit(): void {
this.routerSubscription = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
// Your code
// Use (event.url) to get URL that is being navigated
}
});
}
Remember to unsubscribe on the destroy cicle
ngOnDestroy(): void {
this.routerSubscription?.unsubscribe();
}
Also pay attention depending on your case if is better to use
event instanceof NavigationStart
or
event instanceof NavigationEnd
In the component, you might want to try this:
import {NavigationEnd, NavigationStart, Router} from '@angular/router';
constructor(private router: Router) {
router.events.subscribe(
(event) => {
if (event instanceof NavigationStart)
// start loading pages
if (event instanceof NavigationEnd) {
// end of loading paegs
}
});
}
Location works...
import {Component, OnInit} from '@angular/core';
import {Location} from '@angular/common';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
constructor(private location: Location) {
this.location.onUrlChange(x => this.urlChange(x));
}
ngOnInit(): void {}
urlChange(x) {
console.log(x);
}
}
Capture route change events in the following manner...
import { Component, OnInit, Output, ViewChild } from "@angular/core";
import { Router, NavigationStart, NavigationEnd, Event as NavigationEvent } from '@angular/router';
@Component({
selector: "my-app",
templateUrl: "app/app.component.html",
styleUrls: ["app/app.component.css"]
})
export class AppComponent {
constructor(private cacheComponentObj: CacheComponent,
private router: Router) {
/* Route event types
NavigationEnd
NavigationCancel
NavigationError
RoutesRecognized
*/
router.events.forEach((event: NavigationEvent) => {
//Before Navigation
if (event instanceof NavigationStart) {
switch (event.url) {
case "/app/home":
{
//Do Work
break;
}
case "/app/About":
{
//Do Work
break;
}
}
}
//After Navigation
if (event instanceof NavigationEnd) {
switch (event.url) {
case "/app/home":
{
//Do Work
break;
}
case "/app/About":
{
//Do Work
break;
}
}
}
});
}
}
If you're trying to access the current route while listening to route change:
router.events.pipe(filter(r=>r instanceof NavigationEnd)).subscribe(r=>{
console.log((r as NavigationEnd).url);
});
above most of solutions correct , but i am facing issue this emit multiple times 'Navigation emit' event.when i was change any route this event is triggered. So hear is the complete solution for Angular 6.
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
export class FooComponent implements OnInit, OnDestroy {
private _routerSub = Subscription.EMPTY;
constructor(private router: Router){}
ngOnInit(){
this._routerSub = this.router.events
.filter(event => event instanceof NavigationEnd)
.subscribe((value) => {
//do something with the value
});
}
ngOnDestroy(){
this._routerSub.unsubscribe();
}
}
Updated answer for those who are using Angular9+, By using Router API provided by @angular/router
and listening for route changes
import { Component } from '@angular/core';
import { Router,NavigationEnd } from '@angular/router';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Get Current Url Route Demo';
currentRoute: string;
routeSubscription: subscription;
constructor(private router: Router){
console.log(router.url);
this.routeSubscription = router.events.filter(event => event instanceof NavigationEnd)
.subscribe(event =>
{
this.currentRoute = event.url;
console.log(event);
});
}
}
I would write something like this:
ngOnInit() {
this.routed = this.router.events.map( event => event instanceof NavigationStart )
.subscribe(() => {
} );
}
ngOnDestroy() {
this.routed.unsubscribe();
}
In Angular 7, I have solved using the below function for enabling and disabling the navbar on specific pages.
First you should import NavigationEnd
import { NavigationEnd, Router } from '@angular/router';
navbar.component.ts
public isNavbar=false;
ngAfterViewInit() {
// nabar enable / disable function
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
if(event.url.includes('dashboard')){
this.isNavbar=true;
}else{
this.isNavbar=false;
}
}
});
}
navbar.component.html
<mat-toolbar *ngIf="isNavbar" class="mat-elevation-z1 nav-tool-bar">
<button mat-button routerLink="/dashboard" routerLinkActive="active-list-item"><svg aria-hidden="true" focusable="false" data-prefix="fal" data-icon="paper-plane" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="nav-bar-icon svg-inline--fa fa-paper-plane fa-w-16"><path fill="currentColor" d="M464 4.3L16 262.7C-7 276-4.7 309.9 19.8 320L160 378v102c0 30.2 37.8 43.3 56.7 20.3l60.7-73.8 126.4 52.2c19.1 7.9 40.7-4.2 43.8-24.7l64-417.1C515.7 10.2 487-9 464 4.3zM192 480v-88.8l54.5 22.5L192 480zm224-30.9l-206.2-85.2 199.5-235.8c4.8-5.6-2.9-13.2-8.5-8.4L145.5 337.3 32 290.5 480 32l-64 417.1z" class=""></path></svg>
Campagnes</button>
<button mat-button routerLink="fake" routerLinkActive="active-list-item"><svg aria-hidden="true" focusable="false" data-prefix="fal" data-icon="box-open" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 608 512" class="nav-bar-icon svg-inline--fa fa-box-open fa-w-19"><path fill="currentColor" d="M606.4 143.8L557.5 41c-2.7-5.6-8.1-9-13.9-9C543 32 304 64 304 64S65 32 64.4 32c-5.8 0-11.2 3.5-13.9 9L1.6 143.8c-4.4 9.2.3 20.2 9.6 23l49.5 14.9V393c0 14.7 9.5 27.5 23 31l205.4 54.1c13 3.4 23.7 1.5 29.5 0L524.2 424c13.5-3.6 23-16.4 23-31V181.7l49.5-14.9c9.4-2.8 14-13.8 9.7-23zM73 65.3l180.9 24.3-57.1 99.8-159.9-48.1 36.1-76zm18.2 125.6C208.3 226.1 200.5 224 203.6 224c5.4 0 10.5-2.9 13.3-7.9l71.9-125.5V445L91.2 393V190.9zM516.8 393l-197.6 52V90.5L391.1 216c2.9 5 8 7.9 13.3 7.9 3.1 0-5 2.1 112.4-33.1V393zM411.3 189.3l-57.1-99.8L535 65.3l36.1 76-159.8 48z" class=""></path></svg>
Ressources</button>
<button mat-button routerLink="fake" routerLinkActive="active-list-item"><svg aria-hidden="true" focusable="false" data-prefix="fal" data-icon="life-ring" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="nav-bar-icon svg-inline--fa fa-life-ring fa-w-16"><path fill="currentColor" d="M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm168.766 113.176l-62.885 62.885a128.711 128.711 0 0 0-33.941-33.941l62.885-62.885a217.323 217.323 0 0 1 33.941 33.941zM256 352c-52.935 0-96-43.065-96-96s43.065-96 96-96 96 43.065 96 96-43.065 96-96 96zM363.952 68.853l-66.14 66.14c-26.99-9.325-56.618-9.33-83.624 0l-66.139-66.14c66.716-38.524 149.23-38.499 215.903 0zM121.176 87.234l62.885 62.885a128.711 128.711 0 0 0-33.941 33.941l-62.885-62.885a217.323 217.323 0 0 1 33.941-33.941zm-52.323 60.814l66.139 66.14c-9.325 26.99-9.33 56.618 0 83.624l-66.139 66.14c-38.523-66.715-38.5-149.229 0-215.904zm18.381 242.776l62.885-62.885a128.711 128.711 0 0 0 33.941 33.941l-62.885 62.885a217.366 217.366 0 0 1-33.941-33.941zm60.814 52.323l66.139-66.14c26.99 9.325 56.618 9.33 83.624 0l66.14 66.14c-66.716 38.524-149.23 38.499-215.903 0zm242.776-18.381l-62.885-62.885a128.711 128.711 0 0 0 33.941-33.941l62.885 62.885a217.323 217.323 0 0 1-33.941 33.941zm52.323-60.814l-66.14-66.14c9.325-26.99 9.33-56.618 0-83.624l66.14-66.14c38.523 66.715 38.5 149.229 0 215.904z" class=""></path></svg>Support</button></mat-toolbar>
navbar.component.scss
.mat-toolbar {
padding-top: 2px;
padding-left: 30px;
background-color: #fff;
}
::ng-deep .nav-tool-bar{
button{
.mat-button-focus-overlay{
opacity: 0!important;
}
.nav-bar-icon{
width: 16px;
}
span{
font-size: 15px;
}
}
.active-list-item{
background-color: #c79652;
span{
color: #fff;
font-size: 15px;
svg{
path{
color: #fff;
}
}
}
}
}
Important to changes SCSS .active-list-item background color.
this.router.events.subscribe((event) => {
if (event instanceof NavigationStart) {
this.showProgressBar = true
} else if (event instanceof NavigationEnd) {
this.showProgressBar = false
}
else if (event instanceof NavigationCancel) {
this.showProgressBar = false
}
})
@Ludohen answer is great, but in case you don't want to use instanceof
use the following
this.router.events.subscribe(event => {
if(event.constructor.name === "NavigationStart") {
// do something...
}
});
with this way you can check the current event name as a string and if the event occurred you can do what you planned your function to do.
Event
type is causing an error in Atom that's why I didn't used it –
Antichlor instanceOf
so your example will work in production code too. if(event instanceOf NavigationStart) {
–
Pupiparous if(event instanceof NavigationStart)
–
Belize I am working with angular5 application and i'm facing the same issue . when i go through Angular Documentation they provide best solution for handling router events.check following documentation.
Router Events in Angular Route events in angular5
But specifically for the case provide in question we need NavigationEnd Event
Represents an event triggered when a navigation ends successfully
How to use this ?
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRouteSnapshot, NavigationEnd } from '@angular/router';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit(): void {
//calls this method when navigation ends
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
//calls this stuff when navigation ends
console.log("Event generated");
}
});
}
}
When to use this ?
In my case my application share common dashboard for all users such as users , Admins , but i need to show and hides some navbar options as per user types.
That's why whenever url changes i need to call service method which returns logged in user information as per response i will go for further operations.
You can use the following to detect the route change:
import { Router, ActivatedRoute} from '@angular/router';
constructor(private route: ActivatedRoute) {}
this.router.events.subscribe((event) => {
if(event) {
//do something
}
});
route
isn't used. And property 'events' does not exist on type 'ActivatedRoute'. So basicaly you suggest using router.events
just like older answers… –
Lightness The following KIND of works and may do the tricky for you.
// in constructor of your app.ts with router and auth services injected
router.subscribe(path => {
if (!authService.isAuthorised(path)) //whatever your auth service needs
router.navigate(['/Login']);
});
Unfortunately this redirects later in the routing process than I'd like. The onActivate()
of the original target component is called before the redirect.
There is a @CanActivate
decorator you can use on the target component but this is a) not centralised and b) does not benefit from injected services.
It would be great if anyone can suggest a better way of centrally authorising a route before it is committed. I'm sure there must be a better way.
This is my current code (How would I change it to listen to the route change?):
import {Component, View, bootstrap, bind, provide} from 'angular2/angular2';
import {ROUTER_BINDINGS, RouterOutlet, RouteConfig, RouterLink, ROUTER_PROVIDERS, APP_BASE_HREF} from 'angular2/router';
import {Location, LocationStrategy, HashLocationStrategy} from 'angular2/router';
import { Todo } from './components/todo/todo';
import { About } from './components/about/about';
@Component({
selector: 'app'
})
@View({
template: `
<div class="container">
<nav>
<ul>
<li><a [router-link]="['/Home']">Todo</a></li>
<li><a [router-link]="['/About']">About</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
</div>
`,
directives: [RouterOutlet, RouterLink]
})
@RouteConfig([
{ path: '/', redirectTo: '/home' },
{ path: '/home', component: Todo, as: 'Home' },
{ path: '/about', component: About, as: 'About' }
])
class AppComponent {
constructor(location: Location){
location.go('/');
}
}
bootstrap(AppComponent, [ROUTER_PROVIDERS, provide(APP_BASE_HREF, {useValue: '/'})]);
I do it like this since RC 5
this.router.events
.map( event => event instanceof NavigationStart )
.subscribe( () => {
// TODO
} );
The cleaner way to do this would be to inherit RouteAware
and implement the onNavigationEnd()
method.
It's part of a library called @bespunky/angular-zen.
npm install @bespunky/angular-zen
Make your AppComponent
extend RouteAware
and add an onNavigationEnd()
method.
import { Component } from '@angular/core';
import { NavigationEnd } from '@angular/router';
import { RouteAware } from '@bespunky/angular-zen/router-x';
@Component({
selector : 'app-root',
templateUrl: './app.component.html',
styleUrls : ['./app.component.css']
})
export class AppComponent extends RouteAware
{
protected onNavigationEnd(event: NavigationEnd): void
{
// Handle authentication...
}
}
RouteAware
has other benefits such as:
✨ Any router event can have a handler method (Angular's supported router events).
✨ Usethis.router
to access the router
✨ Usethis.route
to access the activated route
✨ Usethis.componentBus
to access the RouterOutletComponentBus service
im using this way:
class ClassName {
constructor(private router: Router) {
router.events.subscribe((value) => {
// see this
console.log(value instanceof NavigationEnd)
});
}
}
if you just want to check route/query paramater changes like localhost:4200/users/1?edit=1 to localhost:4200/users/2?edit=0 you can use params observable like below.
import { ActivatedRoute, Params } from '@angular/router';
export class SomeClass implements OnInit {
paramFromRoute;
constructor(private route: ActivatedRoute) { }
ngOnInit() {
this.paramFromRoute = this.route.snapshot.params['paramName']; // this one is required for getting it first time
this.route.params.subscribe((params:Params)=>{
this.paramFromRoute = params['paramName'] // whenever route is changed, this function will triggered.
});
// for queryParams you can subscribe to this.route.queryParams
}
}
You do no need to know when route changes in order to protect a route(which is the final goal ).
Angular gives you the CanActivate interface you need to create an auhtguard and asign it to the needed routes that have to be protected
Just make changes on AppRoutingModule like
@NgModule({
imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })],
exports: [RouterModule]
})
Angular 8. Check whether the current route is the base route.
baseroute: boolean;
constructor(
private router: Router,
) {
router.events.subscribe((val: any) => {
if (val.url == "/") {
this.baseroute = true;
} else {
this.baseroute = false;
}
});
}
© 2022 - 2024 — McMap. All rights reserved.