Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
399 views
in Technique[技术] by (71.8m points)

javascript - Stop page from unloading within the beforeunload event handler

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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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/jquery@1.11.3,jquery.ui@1.11.3,jquery.dirtyforms@2.0.0"></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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...