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

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},
  ]}
];

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


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

Tags:

Angular