Angular 8 Cancel or do something before navigation starts

Viewed 6686

I have a scenario where I have a route

<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>

in the controller I would like to cancel the rout navigation based on a value.

export class HeroListComponent implements OnInit {
 cancelRoute : boolean = true

  constructor(
   //some logic where before the route is navigated to, I want it to cancel the route
   // and log a message to console
   //console.log('successfully, canceled route');
  ) {}

EDIT

I do not want this done through a Route Guard, i want this done at the component level. I have a component on the page, that I want to cancel route navigation.

here is my use case.

I have a page which hosts multiple components, If someone leaves the page I want to check with component A and make sure there isnt any unsaved data before they navigate away.

EDIT 2

"I do not want this done through a Route Guard". Why? This is essentially what the CanDeactivate guard exists for. You can definitely use it for your use case with ease.

Correct me If I am wrong, but I would need to put the CanDeactivateGuard On every route for example

RouterModule.forRoot([
  {
    path: 'team/:id',
    component: TeamComponent,
    canDeactivate: ['canDeactivateTeam']
  }

I do not want to have a CanDeactivate on every route, when Only 1 route have foo component inside.

There are many routes, only one route needs foo component and he need to can cancel the route navigation. As far as I know the canDeactivate route gaurd cannot access components created on a route.

EDIT 3

NavigationStart The docs state that this is an event that is fired. I can hook into that event, but I cannot stop the actually navigation. Unless I am wrong NavigatonStart just tells me when it starts navigating not how to stop the navigation.

3 Answers

There is no other way to prevent from navigate with no DeactivateGuard, but! You can make him as injectable.

import { CanDeactivate } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Injectable } from '@angular/core';

@Injectable()
export class DeactivateGuard implements CanDeactivate<HomeComponent> {

    canDeact = true

  canDeactivate() {
    return this.canDeact
  }
}

You can inject it to any component You want and change canDeact to false so You prevent from navigate to other route when job is not done. Still, on default canDeact is true, so if in your route there will be no component foo with will trigger ngOnInit which make guard false and prevent from navigate out.

so guard as above and setup canDeactivate in routing:

{
    path: 'team/:id',
    component: TeamComponent,
    canDeactivate: [DeactivateGuard]
}

Becouse of it is injectable provide it in some root module:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [
    DeactivateGuard
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Assuming, some times foo component will be inside TeamComponent. Just in foo component:

export class FooComponent implements OnInit {

  constructor(private deactGuard: DeactivateGuard) { }

  ngOnInit() {
    this.deactGuard.canDeact = false
  }

  jobDone() {
    this.deactGuard.canDeact = true
  }

}

Try to not paste foo component outside of TeamComponent range. Or develop it correct in ngOnInit so he will not make canDeact false when ever he want's to.

Edit based on the comment below: One possible solution would be the following: Change X.component.html to:

<a (click)='goToCrisisCenter()' routerLinkActive="active">Crisis Center</a>

X.component.ts

constructor(private navigationService: NavigationService) {}

goToCrisisCenter() {
  this.navigationService.tryNavigateTo('/crisis-center');
}

Create NavigationService with:

canNavigate = true;
tryNavigateTo(route:string) {
  if(canNavigate) this.router.navigate([/crisis-center])
}

Inject NavigationService in HeroListComponent and manipulate canNavigate as it suits you.

Try this:

import { Router } from '@angular/router';


export class HeroListComponent implements OnInit {
 cancelRoute : boolean = true

  constructor(provate router: Router) {
   if (cancelRoute) {
     this.router.navigate(["/yourRoute"]);
   } else {
     this.router.navigate(["/yourRouteElse"]); 
   }
}
// If you don't want me to do something the `else`, leave it empty.

I leave you a documentation: https://www.techiediaries.com/angular-router-routerlink-navigate-navigatebyurl/

Related