Abraham
Abraham

Reputation: 333

Angular: Prevent route change if any changes made in the view

If I have a form in a view (Angular). When user tries to navigate away from there, and I want a confirmation message to appear. How can I do that?

Upvotes: 33

Views: 27720

Answers (4)

Viktar K
Viktar K

Reputation: 1528

If your site needs prevent route change for multiple pages, i suppose it might be convenient to use this service:

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


@Injectable()
export class NavPreventerService implements CanActivateChild {
  locks: any = {};

  constructor() {
    // Bonus: If necessary also prevent closing the window:
    window.addEventListener('beforeunload', (event) => {
      if (this.hasRoutingLocks()) {
        event.preventDefault();
        event.returnValue = '';
      }
    });
  }

  canActivateChild() {
    if (this.hasRoutingLocks()) {
      if (confirm('Leave site?')) {
        this.removeAllRoutingLocks();
        return true;
      }
      return false;
    }
    return true;
  }

  setRoutingLock(key: string) {
    this.locks[key] = true;
  }

  removeRoutingLock(key: string) {
    delete this.locks[key];
  }

  removeAllRoutingLocks() {
    this.locks = {};
  }

  hasRoutingLocks(): boolean {
    return !!Object.keys(this.locks).length;
  }
}

When it is necessary to prevent navigation, then in your component call

this.navPreventer.setRoutingLock('quiz-form');

Your application routing file should be like this:

export const appRoutesLocal: Routes  = [
  {path: '', canActivateChild: [NavPreventerService], children: [
    {path: '', component: HomePageComponent},
  ]}
];

Upvotes: 3

JitHiN N JOsE
JitHiN N JOsE

Reputation: 519

You can implement canDeactivate using typescript like

import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { ViewthatyouwantGuard } from './path to your view';

@Injectable()
export class ConfirmDeactivateGuard implements CanDeactivate<ViewthatyouwantGuard> {
    
    canDeactivate(target: ViewthatyouwantGuard) {
        if (target.hasChanges) {
            return window.confirm('Do you really want to cancel?');
        }
        return true;
    }

}

// hasChanges - function in 'ViewthatyouwantGuard' which will return true or false based on unsaved changes

// And in your routing file provide root like 
{path:'rootPath/', component: ViewthatyouwantGuard, canDeactivate:[ConfirmDeactivateGuard]},

// Last but not least, also this guard needs to be registered accordingly:
@NgModule({
    ...
    providers: [
        ...
        ConfirmDeactivateGuard
    ]
 })
 export class AppModule {}

Source: https://blog.thoughtram.io/angular/2016/07/18/guards-in-angular-2.html

Upvotes: 47

Kumar VL
Kumar VL

Reputation: 45

In My example site the user should verify secure pin while navigating to his/her Personal Details page. For all other pages user don't need secure pin. After Secure pin verification success then only he should navigate to "Personal Details" otherwise the user should be in same page.

private routerChangeListener() {
  this.router.events.subscribe(event => {
    if (event instanceof NavigationStart) {
      this.isPersonalDetailsNavigation(event.url);
    }
   });
}

private verfiyIsNavigatingToMedication(url: string) {
   url = url.replace('/', '');
   if (url === 'personal-details') {
    showPinVerficationPopup();
   } else {
    console.log('This Is Not Personal Details Page Navigation');
   }
}

private showPinVerficationPopup() {
  if(verificationSuccess) {
    // This Will Navigate to Personal Details Page
    this.router.navigate(['personal-details']); 
  } else {
    // This Will Prevent Navigation
    this.router.navigate([this.router.url]); 
  } 
}

Upvotes: 0

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657446

CanDeactivate can be used for that. You need to pass the status to a service that is accessible to canDeactivate.

Upvotes: 3

Related Questions