4

www.example.com/templates/create-template

I want to warn users if they leave create-template page. I mean whether they go to another page or to templates.


I use this code to warn users on a page reload and route changes should the form be dirty.

function preventPageReload() {
  var warningMessage = 'Changes you made may not be saved';
  if (ctrl.templateForm.$dirty && !confirm(warningMessage)) {
    return false
  }
}

$transitions.onStart({}, preventPageReload);
window.onbeforeunload = preventPageReload

It works as expected on a page reload and route changes if it is done by clicking on the menu or if you manually change it. However, when I click the back button, it does not fire the warning. only it does if I click the back button for the second time, reload the page, or change route manually.

I am using ui-router. When you click back button, you go from app.templates.create-template state to app.templates state.

How to warn if they press Back button?

isherwood
  • 58,414
  • 16
  • 114
  • 157
mahan
  • 12,366
  • 5
  • 48
  • 83
  • 2
    You might want to look at existing directive made for this purpose, like [angular-unsavedChanges](https://github.com/facultymatt/angular-unsavedChanges), or look at [their implementation](https://github.com/facultymatt/angular-unsavedChanges/blob/develop/src/unsavedChanges.js#L195) – Aleksey Solovey Jul 13 '18 at 11:18
  • @AlekseySolovey I have seen that directive. Unfortunately I can not use it because it is not just a form. It is a HTML template editor too. Moreover, they use `$rooteScrop` to listen for `$locationChangeStart` and `$stateChangeStart`. I have do, but i have still the same problem. – mahan Jul 13 '18 at 11:36

2 Answers2

3

First of all, you are using it wrong:

from https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload:

Note: To combat unwanted pop-ups, some browsers don't display prompts
created in beforeunload event handlers unless the page has been interacted 
with; some don't display them at all. For a list of specific browsers, see the 
Browser_compatibility section.

and

window.onbeforeunload = funcRef
  • funcRef is a reference to a function or a function expression.
  • The function should assign a string value to the returnValue property of the Event object and return the same string.

You cannot open any dialogs in onbeforeunload.

Because you don't need a confirm dialog with onbeforeunload. The browser will do that for you if the function returns a value other than null or undefined when you try to leave the page.

Now, as long as you are on the same page, onbeforeunload will not fire because technically you are still on the same page. In that case, you will need some function that fires before the state change where you can put your confirm dialog.

How you do that depends on the router that you are using. I am using ui-router in my current project and I have that check in the uiCanExit function.


Edit:

You can keep your preventPageReload for state changes in angular. But you need a different function for when the user enters a new address or tries to leave the page via link etc.

Example:

window.onbeforeunload = function(e) {
  if (ctrl.templateForm.$dirty) {
    // note that most broswer will not display this message, but a builtin one instead
    var message = 'You have unsaved changes. Do you really want to leave the site?';
    e.returnValue = message;
    return message;  
  }
}
Daniele Torino
  • 1,714
  • 2
  • 16
  • 22
  • Ok. Do you know how Codepen displays `Leave site?` dialog when you click `back` button ?. – mahan Jul 16 '18 at 10:33
  • Like I said: onbeforeunload needs to return some value other than null or undefined. The "Leave Site?" is a builtin message from chrome. They did this to prevent malicious from misleading the user about the nature of the dialog. – Daniele Torino Jul 16 '18 at 10:42
  • Do you know how can I display it? – mahan Jul 16 '18 at 10:56
1

However, you can use this as below:(using $transitions)

$transitions.onBefore({}, function(transition) {
    return confirm("Are you sure you want to leave this page?");
});

Use $transitions.onBefore insteadof $transitions.onStart.

Hope this may help you. I haven't tested the solutions. This one also can help you.

Hardik Shah
  • 4,042
  • 2
  • 20
  • 41