When navigating sites, users sometimes encounter the popup below when navigating away from a page.
This confirmation is important in times when data might be lost when leaving a page.
Normally, this is done by:
window.onbeforeunload = -> 'Your new changes will be lost.'
However, Backbone applications are single-page applications. In this case, moving to another page in Backbone does not reload a page.
Page navigations are managed by Backbone and unfortunately, this does not trigger the
beforeunload event. It will only trigger when closing the window/tab or pressing the “Refresh” buttons in the browser, not when pressing “Back” or navigation links on the page. Therefore, page transition guard is incomplete (and this is not good).
To solve this problem, Veracross’ backbone-beforepopstate can be used. This is dependent on Backbone.js and jQuery so make sure to include them, too.
backbone-beforepopstate adds 4 events that are triggered during Backbone navigation.
popstate- triggered by pressing ‘Back’ button on browser
pushstate- triggered by navigating by interacting with page elements
beforepopstate- triggered before page transition is applied on
beforepushstate- triggered before page transition is applied on
Since what we’re trying to achieve is to guard page transition before it actually happens,
beforepopstate will be used.
After loading Backbone and jQuery, call
This will override Backbone’s default navigation methods to add mechanisms to trigger the above events.
Constructing the handlers
One thing to keep in mind for handlers is that if it returns
null, it will not guard the page transition (popup won’t be shown). On the other hand, if a string is returned, this string will be shown in the popup.
Handlers can be attached using the following code:
guardPage = (e) -> 'Your new changes will be lost.' dontGuardPage = (e) -> null # Will guard page transition $(window).on('beforepopstate beforepushstate', guardPage) # Will not guard page transition (since handler returns null) $(window).on('beforepopstate beforepushstate', dontGuardPage)
After this, pressing “Back” button and navigating by interacting with page elements are now guarded!
NOTE: Popup for
window.confirm() so instead of the “Leave this Page” and “Stay on this Page” buttons, it shows “OK” and “Cancel”.
The same handlers can be used for
$(window).on('beforepopstate beforepushstate beforeunload', guardPage)
Finally, the page is fully guarded!
The different events received by a single handler can be differentiated by the
typeproperty. Hence, if a slightly different behavior is needed for a certain event, this can be used.
Events from backbone-beforepopstate have a
fragmentproperty. This is the URL fragment that the application would like to transition to. If only certain transitions should be permitted, this URL can be compared with the current URL to show the popup correctly.
# Questionnaire path: `/question/:question_number` guardQuestionnaireExit = (e) -> currentUrl = Backbone.history.fragment toUrl = e.fragment prompt = 'Your answers to the questionnaire will be lost.' questionnairePathRegex = /^question\// # Do not guard if currently not in questionnaire return unless questionnairePathRegex.exec(currentUrl) # Guard if answering questionnaire and closing/refreshing window return prompt if e.type == 'beforeunload' # Guard if going to a page other than questionnaire from questionnaire return prompt unless questionnairePathRegex.exec(toUrl) $(window).on('beforepopstate beforepushstate beforeunload', guardQuestionnaireExit)