How to prevent route changing and show browser prompt

I have upgraded my application from Ember 2.13 to 3.18 and I’ve fixed mostly all changes. But there is an issue with preventing changing the route.

My old code was look like:

`currentPathDidChange: function () {
var that = this;
schedule('afterRender', this, function () {
  if (that.currentRouteName === 'userform') {
    window.onbeforeunload = function () {
      return 'Changes that you made may not be saved.';
    };
  }
}); }.observes('currentPath')`

How to handle it with new Ember?

There’s a section in the guides on preventing transitions using the route willTransition hook. This sounds like it should fit your use case I think…

1 Like

Preventing transitions is probably necessary but not sufficient by itself.

Preventing transitions will stop the user from moving within the Ember app, but it won’t stop them from leaving the Ember app entirely and going to some other web page. For that you still need window.onbeforeunload. So the main question is, where to install and uninstall the onbeforeunload handler.

I like to tie this kind of thing to the lifetime of some particular place in the DOM, because there must be something on screen that is the reason you’re stopping the user, and that place is where it’s good to control the interruption from. So you can make a modifier like this:

// app/modifiers/prevent-unload.js
import Modifier from 'ember-modifier';

export default class PreventUnloadModifier extends Modifier {
  didReceiveArguments() {
    if (this.listener) {
      window.removeEventListener("beforeunload", this.listener);
    }
    this.listener = this.args.positional[0];
    window.addEventListener("beforeunload", this.listener);
  }

  willRemove() {
    window.removeEventListener("beforeunload", this.listener);
  }
}

And then in your template, you can say:

<div {{prevent-unload this.warnUnsavedChanged}}>User Form Here</div>

And implement the warnUnsavedChanges handler in the Component (or Controller) you’re working in:

warnUnsavedChanges(event) {
 if (thereAreUnsavedChanges) {
   event.preventDefault();
   event.returnValue = '';
 }
2 Likes