|
/* |
|
* Adds a confirmation dialogue when the current route contains unsaved changes. |
|
* |
|
* This is tricky because Iron Router doesn't support this out of the box, and |
|
* the reactivity gets in the way. |
|
* In this solution, redirecting to the current route is abused |
|
* as a mechanism to stop the current transition, which Iron Router has no API |
|
* for. Because the redirect would trigger the onStop hook, we keep track of |
|
* whether to run the onStop hook or not ourselves in |
|
* `skipConfirmationForNextTransition`. |
|
* |
|
* When `Session.get('formIsDirty')` returns `true`, the user will be asked |
|
* whether he really wants to leave the route or not. |
|
* |
|
* Further, another confirmation is added in case the browser window is closed |
|
* with unsaved data. |
|
* |
|
* This gist shows the basics of how to achieve a navigation confirmation, |
|
* also known as canceling a route transition. |
|
* This approach may fail if other route hooks trigger reruns of hooks reactively. |
|
* Maybe setting `skipConfirmationForNextTransition` to `true` could help in those |
|
* cases. |
|
*/ |
|
Session.setDefault('formIsDirty', false) |
|
const confirmationMessage = 'You have unsaved data. Are you sure you want to leave?' |
|
|
|
// whether the user should confirm the navigation or not, |
|
// set to `true` before redirecting programmatically to skip confirmation |
|
let skipConfirmationForNextTransition = false |
|
Router.onStop(function () { |
|
// register dependencies immediately |
|
const formIsDirty = Session.equals('formIsDirty', true) |
|
// prevent duplicate execution of onStop route, because it would run again |
|
// after the redirect |
|
if (skipConfirmationForNextTransition) { |
|
skipConfirmationForNextTransition = false |
|
return |
|
} |
|
if (formIsDirty) { |
|
const shouldLeave = confirm(confirmationMessage) |
|
if (shouldLeave) { |
|
Session.set('formIsDirty', false) |
|
return |
|
} |
|
// obtain a non-reactive reference to the current route |
|
let currentRoute |
|
Tracker.nonreactive(function () { |
|
currentRoute = Router.current() |
|
}) |
|
skipConfirmationForNextTransition = true |
|
// "cancel" the transition by redirecting to the same route |
|
// this had to be used because Iron Router doesn't support cancling the |
|
// current transition. `url` contains the query params and hash. |
|
this.redirect(currentRoute.url) |
|
return |
|
} |
|
}) |
|
|
|
// Bonus: confirm closing of browser window |
|
window.addEventListener('beforeunload', event => { |
|
if (Session.get('formIsDirty')) { |
|
// cross-browser requries returnValue to be set, as well as an actual |
|
// return value |
|
event.returnValue = confirmationMessage // eslint-disable-line no-param-reassign |
|
return confirmationMessage |
|
} |
|
}) |
thank you very much.
I had to made some modifications to work on my case
https://gist.github.com/MohammedEssehemy/02c7728cac0157f6024d9f28766d2bca