Before user navigates the page code checks if he edited some of the form fields. If he did, I display a modal window with Yes
and No
buttons. If he clicks no, modal should close and the user remains on that window. If yes - save changes and unload.
$(window).bind('beforeunload', function(){
// check if any field is dirty
if ($('div.form').dirtyForms('isDirty')) {
var modalParams = {
Content: 'You have some unsaved changes, proceed?'
OnSave: navigateAndSave,
OnCancel: cancelNavigate
}
ShowModal(modalParams);
}
})
function navigateAndSave() {
// Do stuff
};
function cancelNavigate() {
// Stop page from unloading and close the modal
};
So what can I do in cancelNavigate
to stop the page from unloading?
This is possible, but only if the user clicks a hyperlink within the page. If the user uses the browser to navigate away from the page, they will get the default browser dialog, which doesn't have an option to save.
Dirty Forms automatically attaches (and removes the handler) to the beforeunload
event, so your attempt to create another event handler will most certainly fail. You should never do this when using Dirty Forms.
You didn't mention which modal dialog framework you wanted to use, so I will just show an example using jQuery UI dialog. Integrating other dialog frameworks is similar. To do so, you might want to check out the source code of the existing pre-built dialogs.
Also, your use case is a bit short-sided. What if the user wants to navigate away and ignore the changes? I have added an example that includes an additional option to do just that.
<html>
<head>
<link rel="stylesheet" type="text/css" href="//cdn.jsdelivr.net/jquery.ui/1.11.3/jquery-ui.min.css" />
</head>
<body>
<script type="text/javascript" src="//cdn.jsdelivr.net/g/[email protected],[email protected],[email protected]"></script>
<script type="text/javascript">
$(document).ready(function() {
// This is required by jQuery UI dialog
$('body').append('<div id="dirty-dialog" style="display:none;" />');
// This must be called before the first call to .dirtyForms
$(document).bind('bind.dirtyforms', function (ev, events) {
var originalOnRefireClick = events.onRefireClick;
events.onRefireClick = function (ev) {
if (saveForm) {
// TODO: Replace this with your AJAX function
// to save the form.
alert('saving form...');
}
originalOnRefireClick(ev);
};
});
// Flag indicating whether or not to save the form on close.
var saveForm = false;
$('.mainForm').dirtyForms({
dialog: {
// Custom properties to allow overriding later using
// the syntax $.DirtyForms.dialog.title = 'custom title';
title: 'Are you sure you want to do that?',
proceedAndSaveButtonText: 'Save Changes & Continue',
proceedAndCancelButtonText: 'Cancel Changes & Continue',
stayButtonText: 'Stay Here',
preMessageText: '<span class="ui-icon ui-icon-alert" style="float:left; margin:2px 7px 25px 0;"></span>',
postMessageText: '',
width: 650,
// Dirty Forms Methods
open: function (choice, message) {
$('#dirty-dialog').dialog({
open: function () {
// Set the focus on close button. This takes care of the
// default action by the Enter key, ensuring a stay choice
// is made by default.
$(this).parents('.ui-dialog')
.find('.ui-dialog-buttonpane button:eq(2)')
.focus();
},
// Whenever the dialog closes, we commit the choice
close: choice.commit,
title: this.title,
width: this.width,
modal: true,
buttons: [
{
text: this.proceedAndSaveButtonText,
click: function () {
// Indicate the choice is the proceed action
choice.proceed = true;
// Pass a custom flag to indicate to save the data first
// in the onRefireClick event
saveForm = true;
$(this).dialog('close');
}
},
{
text: this.proceedAndCancelButtonText,
click: function () {
// Indicate the choice is the proceed action
choice.proceed = true;
// Pass a custom flag to indicate not to save the data
// in the onRefireClick event
saveForm = false;
$(this).dialog('close');
}
},
{
text: this.stayButtonText,
click: function () {
// We don't need to take any action here because
// this will fire the close event handler and
// commit the choice (stay) for us automatically.
$(this).dialog('close');
}
}
]
});
// Inject the content of the dialog using jQuery .html() method.
$('#dirty-dialog').html(this.preMessageText + message + this.postMessageText);
},
close: function () {
// This is called by Dirty Forms when the
// Escape key is pressed, so we will close
// the dialog manually. This overrides the default
// Escape key behavior of jQuery UI, which would
// ordinarily not fire the close: event handler
// declared above.
$('#dirty-dialog').dialog('close');
}
}
});
});
</script>
Change one of the fields below, then click "Go to Google" to try to navigate away.
<form class="mainForm" action="jqueryui.html">
First name: <input type="text" name="fname"><br>
Last name: <input type="text" name="lname"><br>
<input type="submit" value="Submit">
</form>
<a href="http://www.google.com/">Go to Google</a>
</body>
</html>
The example uses custom event binding to attach to the onRefireClick
event handler, which is fired when choice.proceed = true
, but not when it is false
.