jQuery 使用jQuery编辑表单时确认离开页面

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5102602/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 18:34:57  来源:igfitidea点击:

Confirm to leave the page when editing a form with jQuery

jquery

提问by udexter

I am coding a form and I need a function like stackoverflow have: "You have started writing or editing a post.".

我正在编写一个表单,我需要一个像 stackoverflow 这样的函数:“您已经开始编写或编辑帖子。”。

I've looked through the code of stackoverflow to see how they do it but I don't get it at all to apply to my simple form. This is what they have on question.js:

我已经查看了 stackoverflow 的代码以了解他们是如何做到的,但我根本没有将其应用于我的简单表单。这是他们在 question.js 上的内容:

function initNavPrevention(b) {
    if (b.which == "undefined") {
        return
    }
    var a = $("#wmd-input");
    a.unbind("keypress", initNavPrevention);
    setConfirmUnload("You have started writing or editing a post.", a)
}

One of the functions triggers this (I don't know what c is):

其中一个函数触发了这个(我不知道 c 是什么):

if (c) {
    e.keypress(initNavPrevention)
}

And finally they have setConfirmUnload(null);to disable it I suppose.

最后setConfirmUnload(null);,我想他们必须禁用它。

My case is simple. I have a page where I load a <form />via AJAX and I want to prevent when this form is loaded to leave the page without click on the SUBMIT button or if the user clicks CANCEL the form is disabled and the prevention will not popup.

我的情况很简单。我有一个页面,我<form />通过 AJAX加载一个页面,我想阻止加载此表单时离开页面而不单击“提交”按钮,或者如果用户单击“取消”,该表单将被禁用并且不会弹出该表单。

Having this code, can someone tell me how I can include it on my website?

有了这个代码,有人可以告诉我如何将它包含在我的网站上吗?

This is my AJAX function to load the form:

这是我加载表单的 AJAX 函数:

$("#projects_historics_edit_part_1").click(function(){
    $("#ajax-loader").fadeIn('normal');

    $.ajax({
        url: BASE_URL + 'projects/ajax/get_historics_edit_part_1/' + PROJECT_ID,
        type: "POST",
        success: function(data) {
            $("div#projects_historics_part_1").html(data);

            $("#client").autocomplete(client_autcomplete_options);

            var inicofin = $("#initdate, #findate").datepicker(initdate_datepicker_options);
        }
    });

    $("#ajax-loader").fadeOut("normal");

    return false;    
});

Thank you in advance!

先感谢您!

回答by betamax

You can do this using window.onbeforeunloadlike this:

你可以这样使用window.onbeforeunload

window.onbeforeunload = function() {
    return 'Are you sure you want to navigate away from this page?';
};

So in your code, you would put that inside the successcallback of your $.ajaxcall.

所以在你的代码中,你会把它放在success你的$.ajax调用的回调中。

To unset the confirmation, you can do this:

要取消设置确认,您可以执行以下操作:

window.onbeforeunload = null;

Also, see this answer: How can I override the OnBeforeUnload dialog and replace it with my own?

另外,请参阅此答案:如何覆盖 OnBeforeUnload 对话框并将其替换为我自己的?

回答by Wasim A.

This is how in JQuery

这就是 JQuery 中的方式

$('#form').data('serialize',$('#form').serialize());
  // On load save form current state

$(window).bind('beforeunload', function(e){
    if($('#form').serialize()!=$('#form').data('serialize'))return true;
    else e=null;
    // i.e; if form state change show box not.
});

You can Google JQuery Form Serialize function, this will collect all form inputs and save it in array. I guess this explain is enough :)

您可以使用 Google JQuery Form Serialize 函数,这将收集所有表单输入并将其保存在数组中。我想这个解释就足够了:)

回答by Sam Watkins

I made a general function for this based on Wasim's excellent answer:

我根据Wasim的出色回答为此做了一个通用功能:

var confirm_nav_ignore = [];
function confirm_nav() {
    function save_form_state($form) {
        var old_state = $form.serialize();
        $form.data('old_state', old_state);
    }

    // On load, save form current state
    $('form').each(function() {
        save_form_state($(this));
    });

    // On submit, save form current state
    $('form').submit(function() {
        save_form_state($(this));
    });

    // strip fields that we should ignore
    function strip(form_data) {
        for (var i=0; i<confirm_nav_ignore.length; i++) {
            var field = confirm_nav_ignore[i];
            form_data = form_data.replace(new RegExp("\b"+field+"=[^&]*"), '');
        }   
        return form_data;
    }

    // Before unload, confirm navigation if any field has been edited
    $(window).on('beforeunload', function(e) {
        var rv;
        $('form').each(function() {
            var $form = $(this);
            var old_state = strip($form.data('old_state'));
            var new_state = strip($form.serialize());
            if (new_state != old_state) {
                rv = '';
            }   
        }); 
        return rv;
    }); 
}

// I call it at the end of the on-load handler:
$(function() {
    confirm_nav();
});

Changes:

变化:

  1. Allows to submit a form without confirmation.
  2. Works with multiple forms, using $('form').each(...)
  3. Does not depend on the form having id="form"
  4. Returns '' as the custom confirmation message, instead of true which displays "true" in Chrome.
  5. For difficult pages, it can be told to ignore certain form fields.
  6. Run it from the end of the on-load handler... seems like a good idea.
  7. It's generic enough, so we can use it on every page in a site.
  1. 允许在没有确认的情况下提交表单。
  2. 适用于多种形式,使用 $('form').each(...)
  3. 不依赖于具有 id="form" 的表单
  4. 返回 '​​' 作为自定义确认消息,而不是在 Chrome 中显示“true”的 true。
  5. 对于困难的页面,可以告诉它忽略某些表单字段。
  6. 从加载处理程序的末尾运行它......似乎是个好主意。
  7. 它足够通用,因此我们可以在站点的每个页面上使用它。

It might look over-engineered, but that's what I had to do to make it work correctly in a real web app.

它可能看起来过度设计,但这是我必须做的才能使其在真正的 Web 应用程序中正常工作。

Thanks to Wasim, for the great idea to use JQuery $(form).serialize().

感谢 Wasim,他提出了使用 JQuery $(form).serialize() 的好主意。

回答by Danil Pyatnitsev

Based on Wasim A. answer. That code snipped looks great, but if I clicked to submit button I have an notification too. I think this is better:

基于Wasim A. 答案。剪下的代码看起来很棒,但如果我点击提交按钮,我也会收到通知。我认为这样更好:

$(document).ready(function() {
    let form = $('#form');
    form.data('serialize', form.serialize());
    
    // if submit clicked - pass user to save form
    form.find('submit').on('click', function () {
        $(window).off('beforeunload');
    });
});



  // On load save form current state

$(window).bind('beforeunload', function(e){
    let form = $('#form');
    if(form.serialize() !== form.data('serialize')) {
      return true;
    } else {
    // i.e; if form state change show box not.
      e=null;
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

回答by Gassan

small optimization of excellent Sam's answer:

优秀山姆回答的小优化:

var confirm_nav_ignore = [];
function confirm_nav() {
    var $forms = $('form'); // if you need it add .filter('#your_form_id');

    function save_form_state() {
        var $form = $(this),
            old_state = $form.serialize();
        $form.data('old_state', old_state);
    }

    $forms
        // On load, save form current state
        .each(save_form_state)
        // On submit, save form current state
        .submit(save_form_state)
    ;

    // strip fields that we should ignore
    function strip(form_data) {
        for (var i = 0; i < confirm_nav_ignore.length; i++) {
            var field = confirm_nav_ignore[i];
            form_data = form_data.replace(new RegExp("\b" + field + "=[^&]*"), '');
        }

        return form_data;
    }

    // Before unload, confirm navigation if any field has been edited
    $(window).on('beforeunload', function(e) {
        var rv = undefined;

        $forms.each(function() {
            var $form = $(this);
            var old_state = strip($form.data('old_state'));
            var new_state = strip($form.serialize());
            if (new_state !== old_state) {
                e.preventDefault();
                rv = '';
            }
        });

        return rv;
    });
}
// I call it at the end of the on-load handler:
$(confirm_nav);

tested on last chrome, firefox and safari

在最后一个 chrome、firefox 和 safari 上测试