Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 5 add event before the route change

I'm want to add a alert dialog before the user click on the <a href="..."> link.

There are 2 types of <a> link

  1. Redirect within Angular scope <a routerLink="/path/to/dest">
  2. Redirect outside of Angular app <a href="http://www.somewhere.com" target="_blank">

I want to able to show an alert box when user try to go outside of Angular scope

Alert dialog

I want to apply to all <a> click event (kind like pre-hook)

Any way to achieve this?

like image 701
Js Lim Avatar asked Dec 27 '17 04:12

Js Lim


People also ask

What are router events in angular?

Some of the useful events are route change start ( NavigationStart ) and route change end ( NavigationEnd ). In this tutorial, we learn what is router events are and how to listen to them using Example code. Applies to: Angular 2 to the latest edition of i.e. Angular 8. Angular 9, Angular 10, Angular 11, Angular 12

What are the navigation events in angular?

The Angular Route r raises events when it navigates from one route to another route. It raises several events such as NavigationStart, NavigationEnd, NavigationCancel, NavigationError, ResolveStart, etc.

How to detect route state changes in Angular 8?

Detecting Route state changes can be done by subscribing to the router and listening to the events being emitted. In the example below, you will see all the router events that you can listen to in Angular 8.

What are the steps of routing in angular?

the Angular router stats the navigation. the Router lazy loads a route configuration. after a route has been lazy-loaded. the Router parses the URL and the routes are recognized. the Router begins the Guards phase of routing. the Router begins activating a route's children.


3 Answers

For links to other views of your Angular application, you can implement a CanDeactivate route guard. You will find an example in this stackblitz, for the "Home" page.

The links that navigate outside of the application should trigger the event handler bound to window:beforeunload (shown in HomeViewComponent below). However, its behavior seems to be different in Firefox (a confirmation box is shown) and in Chrome (no confirmation box shown). That event cannot be tested with stackblitz, as far as I can see.


In app.module:

...
import { AppRoutingModule } from './app.routing.module';
import { DeactivateGuard } from './views/home/deactivate-guard';

@NgModule({
  imports: [ 
    AppRoutingModule, 
    ... 
  ],
  providers: [
    DeactivateGuard
  ],
  ...
})

In app.routing.module:

...
import { RouterModule } from '@angular/router';
import { DeactivateGuard } from './views/home/deactivate-guard';

@NgModule({
  imports: [
    RouterModule.forRoot([
      ...
      {
        path: 'home',
        component: HomeViewComponent,
        canDeactivate: [DeactivateGuard]
      },
      ...
    ])
  ],
  exports: [
    RouterModule,
  ],
  ... 
})

In home/deactivate-guard:

import { CanDeactivate } from '@angular/router';
import { HomeViewComponent } from './home.component';

export class DeactivateGuard implements CanDeactivate<HomeViewComponent> {

  canDeactivate(component: HomeViewComponent) {
    return component.canDeactivate();
  }
}

In home.component:

import { Component, HostListener } from '@angular/core';
...

@Component({
  ...
})
export class HomeViewComponent {

  @HostListener("window:beforeunload", ["$event"]) unloadHandler(event: Event) {
      event.returnValue = false;
  }

  canDeactivate() {
    return confirm("Do you want to leave?");
  }

  ...
}
like image 81
ConnorsFan Avatar answered Oct 18 '22 15:10

ConnorsFan


so Angular provides canActivate to make sure if you want to activate the route or not based on certain condition. You can

const routes: Routes = [
    {path: '/some-path', canActivate:[AuthGuard]}
];

Your canActivate service

import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild } from '@angular/router';

@Injectable()
export class AuthGuard implements CanActivate, CanActivateChild {

  canActivate() {
    //ask if he really wants to route.
    console.log('i am checking to see if you are logged ')
    return true;
  }

  canActivateChild() {
    console.log('checking child route access');
    return true;
  }

}

In the canActivate you can display a generic model to ask whether he wants to route to URL or not, and based on that you can control which link can have it and which not. You can even write logic for all the routing whether it be coming from anchor tag or anything else.

like image 25
manish kumar Avatar answered Oct 18 '22 15:10

manish kumar


You can implement route guard which checks for your condition and then decide whether to redirect to clicked url or not depending upon your choice.

If you are following angular cli then you can simply install route guard by running :

ng g guard my-new-guard

Import guard file in app.module.ts and add it into providers array. In routing file add route guard to the paths on which you want to check for the condition. Like :

const appRoutes: Routes = [
    {path: '/your-path', canActivate: [route-guard]}
];

In your route-guard file you can implement your logic like this :

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot} from '@angular/router';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthGuardGuard implements CanActivate {
    canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

            if(!state.url.startsWith('/')){
               // I have check here for starting single slash for all your angular local routes. You can also check for http or https whichever you want according to your need
               // here you can trigger your modal pop-up on its 'OK' button return true to redirect to the url
               return true;   // or return false on 'Cancel' button of modal pop-up for cancelling route if condition doesn't fullfill
            }
    }
}
like image 23
Mohsin Hasan Avatar answered Oct 18 '22 17:10

Mohsin Hasan