Warn user of unsaved changes before leaving page

jquery warn before leaving page
unsaved changes warning message
confirm navigation leave this page javascript
leave page stay on page popup javascript
unsaved changes dialog
warn user before leaving web page with unsaved changes angular
jquery are you sure
are you sure you want to leave this page javascript disable

I would like to warn users of unsaved changes before they leave a particular page of my angular 2 app. Normally I would use window.onbeforeunload, but that doesn't work for single page applications.

I've found that in angular 1, you can hook into the $locationChangeStart event to throw up a confirm box for the user, but I haven't seen anything that shows how to get this working for angular 2, or if that event is even still present. I've also seen plugins for ag1 that provide functionality for onbeforeunload, but again, I haven't seen any way to use it for ag2.

I'm hoping someone else has found a solution to this problem; either method will work fine for my purposes.

The router provides a lifecycle callback CanDeactivate

for more details see the guards tutorial

class UserToken {}
class Permissions {
  canActivate(user: UserToken, id: string): boolean {
    return true;
  }
}
@Injectable()
class CanActivateTeam implements CanActivate {
  constructor(private permissions: Permissions, private currentUser: UserToken) {}
  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean>|Promise<boolean>|boolean {
    return this.permissions.canActivate(this.currentUser, route.params.id);
  }
}
@NgModule({
  imports: [
    RouterModule.forRoot([
      {
        path: 'team/:id',
        component: TeamCmp,
        canActivate: [CanActivateTeam]
      }
    ])
  ],
  providers: [CanActivateTeam, UserToken, Permissions]
})
class AppModule {}

original (RC.x router)

class CanActivateTeam implements CanActivate {
  constructor(private permissions: Permissions, private currentUser: UserToken) {}
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):Observable<boolean> {
    return this.permissions.canActivate(this.currentUser, this.route.params.id);
  }
}
bootstrap(AppComponent, [
  CanActivateTeam,
  provideRouter([{
    path: 'team/:id',
    component: Team,
    canActivate: [CanActivateTeam]
  }])
);

Warn users before leaving a page with unsaved changes, Browsers have provided a built-in prompt that warns users before leaving certain pages. The user then has the option of leaving the page or  User has a form with updated data, and after changing the value of some <input> or <select>, the user tries to close the tab or window, or hits “Back” button on the browser. The user has a form with updated data, but this form is really a “sub form” which is entirely AJAX submitted.

To also cover guards against browser refreshes, closing the window, etc. (see @ChristopheVidal's comment to Günter's answer for details on the issue), I have found it helpful to add the @HostListener decorator to your class's canDeactivate implementation to listen for the beforeunload window event. When configured correctly, this will guard against both in-app and external navigation at the same time.

For example:

Component:

import { ComponentCanDeactivate } from './pending-changes.guard';
import { HostListener } from '@angular/core';
import { Observable } from 'rxjs/Observable';

export class MyComponent implements ComponentCanDeactivate {
  // @HostListener allows us to also guard against browser refresh, close, etc.
  @HostListener('window:beforeunload')
  canDeactivate(): Observable<boolean> | boolean {
    // insert logic to check if there are pending changes here;
    // returning true will navigate without confirmation
    // returning false will show a confirm dialog before navigating away
  }
}

Guard:

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

export interface ComponentCanDeactivate {
  canDeactivate: () => boolean | Observable<boolean>;
}

@Injectable()
export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> {
  canDeactivate(component: ComponentCanDeactivate): boolean | Observable<boolean> {
    // if there are no pending changes, just allow deactivation; else confirm first
    return component.canDeactivate() ?
      true :
      // NOTE: this warning message will only be shown when navigating elsewhere within your angular app;
      // when navigating away from your angular app, the browser will show a generic warning message
      // see http://stackoverflow.com/a/42207299/7307355
      confirm('WARNING: You have unsaved changes. Press Cancel to go back and save these changes, or OK to lose these changes.');
  }
}

Routes:

import { PendingChangesGuard } from './pending-changes.guard';
import { MyComponent } from './my.component';
import { Routes } from '@angular/router';

export const MY_ROUTES: Routes = [
  { path: '', component: MyComponent, canDeactivate: [PendingChangesGuard] },
];

Module:

import { PendingChangesGuard } from './pending-changes.guard';
import { NgModule } from '@angular/core';

@NgModule({
  // ...
  providers: [PendingChangesGuard],
  // ...
})
export class AppModule {}

NOTE: As @JasperRisseeuw pointed out, IE and Edge handle the beforeunload event differently from other browsers and will include the word false in the confirm dialog when the beforeunload event activates (e.g., browser refreshes, closing the window, etc.). Navigating away within the Angular app is unaffected and will properly show your designated confirmation warning message. Those who need to support IE/Edge and don't want false to show/want a more detailed message in the confirm dialog when the beforeunload event activates may also want to see @JasperRisseeuw's answer for a workaround.

Warning user before closing or leaving page with unsaved , This even will trigger whenever the user is trying to leave the page by <h1 id="​home">Warn before leaving the page</h1>; <script>; // Warning before leaving  In this video, we will discuss how to warn the user before leaving web page with unsaved changes. Let us understand this with an example. Here is what we want to do

The example with the @Hostlistener from stewdebaker works really well, but I made one more change to it because IE and Edge display the "false" that is returned by the canDeactivate() method on the MyComponent class to the end user.

Component:

import {ComponentCanDeactivate} from "./pending-changes.guard";
import { Observable } from 'rxjs'; // add this line

export class MyComponent implements ComponentCanDeactivate {

  canDeactivate(): Observable<boolean> | boolean {
    // insert logic to check if there are pending changes here;
    // returning true will navigate without confirmation
    // returning false will show a confirm alert before navigating away
  }

  // @HostListener allows us to also guard against browser refresh, close, etc.
  @HostListener('window:beforeunload', ['$event'])
  unloadNotification($event: any) {
    if (!this.canDeactivate()) {
        $event.returnValue = "This message is displayed to the user in IE and Edge when they navigate without using Angular routing (type another URL/close the browser/etc)";
    }
  }
}

Prevent leaving the page using plain JavaScript, Link for all dot net and sql server video tutorial playlists http://www.youtube.com/​user Duration: 10:03 Posted: Mar 12, 2015 Binding the input event to all inputs (and textareas and selects) on your page won’t work on older browsers and, like all event handling solutions mentioned above, doesn’t support undo. When a user changes a textbox and then undoes that, or checks and unchecks a checkbox, the form is still considered dirty.

I've implemented the solution from @stewdebaker which works really well, however I wanted a nice bootstrap popup instead of the clunky standard JavaScript confirm. Assuming you're already using ngx-bootstrap, you can use @stwedebaker's solution, but swap the 'Guard' for the one I'm showing here. You also need to introduce ngx-bootstrap/modal, and add a new ConfirmationComponent:

Guard

(replace 'confirm' with a function that will open a bootstrap modal - displaying a new, custom ConfirmationComponent):

import { Component, OnInit } from '@angular/core';
import { ConfirmationComponent } from './confirmation.component';

import { CanDeactivate } from '@angular/router';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BsModalService } from 'ngx-bootstrap/modal';
import { BsModalRef } from 'ngx-bootstrap/modal';

export interface ComponentCanDeactivate {
  canDeactivate: () => boolean | Observable<boolean>;
}

@Injectable()
export class PendingChangesGuard implements CanDeactivate<ComponentCanDeactivate> {

  modalRef: BsModalRef;

  constructor(private modalService: BsModalService) {};

  canDeactivate(component: ComponentCanDeactivate): boolean | Observable<boolean> {
    // if there are no pending changes, just allow deactivation; else confirm first
    return component.canDeactivate() ?
      true :
      // NOTE: this warning message will only be shown when navigating elsewhere within your angular app;
      // when navigating away from your angular app, the browser will show a generic warning message
      // see http://stackoverflow.com/a/42207299/7307355
      this.openConfirmDialog();
  }

  openConfirmDialog() {
    this.modalRef = this.modalService.show(ConfirmationComponent);
    return this.modalRef.content.onClose.map(result => {
        return result;
    })
  }
}
confirmation.component.html
<div class="alert-box">
    <div class="modal-header">
        <h4 class="modal-title">Unsaved changes</h4>
    </div>
    <div class="modal-body">
        Navigate away and lose them?
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-secondary" (click)="onConfirm()">Yes</button>
        <button type="button" class="btn btn-secondary" (click)="onCancel()">No</button>        
    </div>
</div>
confirmation.component.ts
import { Component } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { BsModalRef } from 'ngx-bootstrap/modal';

@Component({
    templateUrl: './confirmation.component.html'
})
export class ConfirmationComponent {

    public onClose: Subject<boolean>;

    constructor(private _bsModalRef: BsModalRef) {

    }

    public ngOnInit(): void {
        this.onClose = new Subject();
    }

    public onConfirm(): void {
        this.onClose.next(true);
        this._bsModalRef.hide();
    }

    public onCancel(): void {
        this.onClose.next(false);
        this._bsModalRef.hide();
    }
}

And since the new ConfirmationComponent will be displayed without using a selector in an html template, it needs to be declared in entryComponents in your root app.module.ts (or whatever you name your root module). Make the following changes to app.module.ts:

app.module.ts
import { ModalModule } from 'ngx-bootstrap/modal';
import { ConfirmationComponent } from './confirmation.component';

@NgModule({
  declarations: [
     ...
     ConfirmationComponent
  ],
  imports: [
     ...
     ModalModule.forRoot()
  ],
  entryComponents: [ConfirmationComponent]

Warn user before leaving web page with unsaved changes, Dear, I have a form in which i have some fields what i want is that if a user navigates away from the page with unsaved changes then he will be  When a user is editing data on a web page and they navigate to another page before saving that data, their changes will be lost. Here&#39;s some handy jQuery to warn the user any time they attempt to navigate to another page with unsaved changes and give them the option of staying on the current page to save those changes.

The solution was easier than expected, don't use href because this isn't handled by Angular Routing use routerLink directive instead.

How to Warn user before leaving web page with unsaved changes , I want to warn user before leaving page with unsaved changes on salesforce standerd object. Thank You. Long, correct answer: You also don't want to show this message when the user hasn't changed anything on your forms. One solution is to use the beforeunload event in combination with a "dirty" flag, which only triggers the prompt if it's really relevant.

Warn user before leaving page with unsaved changes, The task is to show alert message like "Are you sure you want to leave this page" when user changed some data in form, but haven't submit it. javascript stay Warn user before leaving web page with unsaved changes. save changes before leaving page (11) Based on the previous answers, and cobbled together from various places in stack overflow, here is the solution I came up with which handles the case when you actually want to submit your changes:

Alert when leaving page with unsaved form (Example), Hey we all have gone thru the job of making sure a user doesn't have pending modifications to be saved before navigating away from our page. If  Warn on Unsaved Changes: Yes. but on my component Popup Lov, I am setting it as: Warn on Unsaved Changes: Ignore. Now, when the value is changed in Popup Lov and some button is clicked to submit the page, it warns me for unsaved changes.

Warn user about unsaved changes before leaving the page, Before we get into the code, what is the tl;dr from my video? ‍ . use the beforeunload event to warn a user they're going to close your page, but only when it's important returnValue = 'You have unfinished changes!'; } });. Prevent leaving the page using plain JavaScript. In many case, but espeically in single-page applications when there is some unsaved data in the browser you might want to make sure the user does not accidently leave the page without first saving the data. This can be achived using the onbeforeunload (read "on before unload") event.

Comments
  • It does work for single page applications, when you try to close the page/tab. So any answers to the question would be only a partial solution if they ignore that fact.
  • Unlike what the OP asked for, CanDeactivate is -currently- not hooking on the onbeforeunload event (unfortunately). Meaning that if the user tries to navigate to an external URL, close the window, etc. CanDeactivate will not be triggered. It seems to work only when the user is staying within the app.
  • @ChristopheVidal is correct. Please see my answer for a solution that also covers navigating to an external URL, closing the window, reloading the page, etc.
  • This works when changing routes. What if it's SPA ? Any other way to achieve this ?
  • stackoverflow.com/questions/36763141/… You would this need with routes as well. If the window is closed or navigated away from the current site canDeactivate won't work.
  • This works really well @stewdebaker! I have one addition to this solution, see my answer below.
  • import { Observable } from 'rxjs/Observable'; is missing from ComponentCanDeactivate
  • I had to add @Injectable() to the PendingChangesGuard class. Also, I had to add PendingChangesGuard to my providers in @NgModule
  • I had to add import { HostListener } from '@angular/core';
  • It's worth noticing that you must return a boolean in case you are being navigated away with beforeunload. If you return an Observable, it will not work. You may want to change your interface for something like canDeactivate: (internalNavigation: true | undefined) and call your component like this: return component.canDeactivate(true). This way, you can check if you are not navigating away internally to return false instead of an Observable.
  • Good catch @JasperRisseeuw! I didn't realize that IE/Edge handled this differently. This is a very useful solution for those who need to support IE/Edge and don't want the false to show in the confirm dialog. I made a small edit to your answer to include the '$event' in the @HostListener annotation, since that is required in order to be able to access it in the unloadNotification function.