Router Guards in Angular 8

2.8k views Asked by At

I created an application where the user inputs data. On that application, I want to implement router guards to deny the user to go back on-page so that they don't lose their data. If the user clicks on the back button on the browser, it reloads page instead of going back?

I am thinking to use canDeactivate to deny access to the previous page and Angular Location to determine what page users are on then reload that page. But I don't how to implement this.

1

There are 1 answers

10
Rafi Henig On BEST ANSWER

1. Create Service for CanDeactivate Guard

First you have to create an interface that will declare canDeactivate method and using this interface you will create a service that will act as canDeactivate guard. This service will define canDeactivate method as following:

deactivate.guard.ts:

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

export interface CanComponentDeactivate {
  canDeactivate(): boolean;
}

@Injectable()
export class DeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
  canDeactivate(component: CanComponentDeactivate): boolean {

    /*
    The return value would be true, unless the canActivate function, 
    defined on the component returns false,
    in which case the function will open a Dialog Box,
    to ask if we want to stay on the page or leave the page.
    */
    if (component.canDeactivate()) return true;
    else return confirm('You have unsaved changes!') ? true : false;

  }
}

The interface has declared canDeactivate method whose return type is boolean. In the service code, we called canDeactivate method using component instance.

2. Configure CanDeactivate Guard Service in Application Routing Module

app.module.ts:

import { CanDeactivateGuard } from './can-deactivate-guard.service';

------
@NgModule({
  ------
  providers: [ 
    CanDeactivateGuard
  ]
})
export class AppRoutingModule { } 

3. Create canDeactivate() method within Your Component

formComponent.ts:

import { Component, HostListener } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { CanComponentDeactivate } from 'src/app/deactivate.guard';

@Component({
  selector: 'app-form',
  templateUrl: './form.component.html',
  styleUrls: ['./form.component.scss']
})
export class FormComponent implements CanComponentDeactivate {
  saved: boolean;
  form: FormGroup;
  constructor(private fb: FormBuilder) {
    this.form = this.fb.group({
      name: ['']
    });
  }

  /* Prevent page reloading */
  @HostListener('window:beforeunload', ['$event'])
  canReload(e) {
    if (!this.canDeactivate()) e.returnValue = true;
  }

  submit = () => this.saved = true;
  canDeactivate = () => this.saved || !this.form.dirty;
}

4. Add CanDeactivate Guard to Component Route in Routing Module

You need to add our CanDeactivate guard .i.e. DeactivateGuard to component route in routing module using canDeactivate attribute.

app-routing.module.ts:

const routes: Routes = [
  {
    path: 'home',
    component: FormComponent,
    canDeactivate: [DeactivateGuard]
  },
  { path: 'next', component: NextComponent },

  { path: '', redirectTo: '/home', pathMatch: 'full' }
];

You might as well consider storing your data in a service as it might be a better choice.