Prevent user from losing unsaved data

Table of contents
Reading Time: 3 minutes

angular-logoThere are many instances where a user fills some details in the form, edit their details, or secure the form in such a way that if someone navigates away or closes the browser tab, they should be prompted to confirm that they really want to leave the form with unsaved data.

Whenever these kind instances occur you will see an alert appear on the top of your browser like this:
Screenshot-from-2019-11-08-16-53-30

 Here we have  2 different ways of implementing these functionalities: 

  • When a user closes or refreshes the tab.
  • When navigation is changed (user clicks back or forward).

So, let go-ahead with the first implementation:

1: When a user closes or refreshes the tab:

We need to register window:beforeunload and show a message if the user has unsaved data. The beforeunload event is fired when the window, the document, and its resources are about to be unloaded. The document is still visible and the event is still cancelable at this point.

This event enables a web page to trigger a confirmation dialog asking the user if they really want to leave the page. If the user confirms, the browser navigates to the new page, otherwise, it cancels the navigation.

For eg:

@HostListener('window:beforeunload', ['$event'])
public onPageUnload($event: BeforeUnloadEvent) {
  if (this.hasUnsavedData()) {
    $event.returnValue = true;
  }
}

2: When the user navigates to another route (Navigation changed event):

For the implementation of navigation changed events you need to initially create a canDeactivate interface. It is an interface that a class can implement to be a guard deciding if a route can be deactivated. If all guards return true navigation will continue. If any guard returns false, navigation will be canceled. If any guard returns a UrlTree, current navigation will be canceled and new navigation will be kicked off to the UrlTree returned from the guard.

  • Initially, we need to write the import statement for canDeactivate which imports it from ‘@angular/router’. 
import { CanDeactivate } from '@angular/router';
  • Then we create an interface for the HasUnsavedData method and import it as well in a guard file/component.
export interface HasUnsavedData {
  hasUnsavedData(): boolean;
}
  • Add the path to the route config file.
{path:'user/new',component:UserFormComponent,canDeactivate: [CanDeactivateGuard]}

Add CanDeactivate to the ngModule providers.

Now, we write the main method to handle this event and showing the popups for displaying the message for unsaved data in the guard file.

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

import { HasUnsavedData } from './core.interface';

@Injectable()
export class HasUnsavedDataGuard implements CanDeactivate {
  canDeactivate(component: HasUnsavedData): boolean {
    if (component.hasUnsavedData && component.hasUnsavedData()) {
      return confirm('You have some unsaved form data.
 Are you sure, you want to leave this page?');
    }
    return true;
  }
}

We will have to implement the method, CanDeactivate, which gets the component instance and returns a true or false. In this example, true will be returned if the message popped up and the user confirmed. Otherwise, the route won’t be changed.

Conclusion: To sum up all the blog, as a best practice we should create a generic component to handle any form component. This abstract component will be registered to the browser event and the angular guard will invoke its API: CanDeactivate. It will return that data is unsaved when the form is actually left, not submitted and dirty.

Thanks for reading!!!

Written by 

Nitin Arora is a Software Consultant at Knoldus Software LLP. He has done MCA from the Banarsidas Chandiwala Institute of Information technology, Delhi(GGSIPU). He has a graduation degree in BCA from Jamia Hamdard. He has a sound knowledge of various programming languages like C, C++, Java. Also has a deep interest in frontend development like Html, CSS, Angular, Javascript, ionic, react with redux, bootstrap. He is currently working in frontend technologies like React, Html, SCSS, Bootstrap, and Typescript. He is a focused, hardworking, team-oriented member and always exploring new Technologies, His hobbies are to play cricket, volleyball, and do coding.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading