Skip to content

Instantly share code, notes, and snippets.

@dferber90
Last active August 3, 2018 09:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dferber90/acf560226fe76fe91534 to your computer and use it in GitHub Desktop.
Save dferber90/acf560226fe76fe91534 to your computer and use it in GitHub Desktop.
Confirming Navigation with Iron Router (canceling route transition)
/*
* 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
}
})
@MohammedEssehemy
Copy link

thank you very much.
I had to made some modifications to work on my case

https://gist.github.com/MohammedEssehemy/02c7728cac0157f6024d9f28766d2bca

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment