提醒表单中未保存的更改


72

我想在主文件中编写Jquery代码,以便如果用户更改页面并且存在未保存的更改,则用户应该收到警报。我从中得到一个答案:链接

但是,在大多数解决方案中,我将必须在所有页面上编写代码。我希望它仅在一个地方编写,这样每个人都不必担心在其模块中编写它。我的代码是这样的:

<script type="text/javascript">
    var isChange;
    $(document).ready(function () {
        $("input[type='text']").change(function () {
            isChange = true;
        })
    });
    $(window).unload(function () {
        if (isChange) {
            alert('Handler for .unload() called.');
        }
    });

</script>

但是,每次我在文本框中进行更改时,不会触发.change()事件。

代码有什么问题?

编辑:我将.change()更改为.click并被解雇了。我正在使用jQuery 1.4.1 ..是否由于jquery版本的change()无法正常工作?


是所有输入字段都是静态的,还是将某些动态添加到表单中(或由Ajax加载)?
2012年

4
但是,在大多数解决方案中,我将必须在所有页面上编写代码。为什么不使用外部脚本文件?
未定义的2012年

@Raminson是正确的,编写一个外部js文件,然后将其包含在页面中。
2012年

Answers:


121

这就是我正在使用的方法,将所有这些代码放在一个单独的JS文件中,并将其加载到您的头文件中,因此您无需一次又一次地复制它:

var unsaved = false;

$(":input").change(function(){ //triggers change in all input fields including text type
    unsaved = true;
});

function unloadPage(){ 
    if(unsaved){
        return "You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?";
    }
}

window.onbeforeunload = unloadPage;

找不到$的EDIT:

只能由以下三种原因之一导致此错误:

  1. 您的JavaScript文件未正确加载到页面中
  2. 您有一个拙劣的jQuery版本。发生这种情况的原因是有人编辑了核心文件,或者插件可能覆盖了$变量。
  3. 您需要在页面完全加载之前以及jQuery完全加载之前运行JavaScript。

确保所有JS代码都放置在此代码中:

$(document).ready(function () {
  //place above code here
});

编辑以保存/发送/提交按钮例外

$('#save').click(function() {
    unsaved = false;
});

编辑以使用动态输入

// Another way to bind the event
$(window).bind('beforeunload', function() {
    if(unsaved){
        return "You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?";
    }
});

// Monitor dynamic inputs
$(document).on('change', ':input', function(){ //triggers change in all input fields including text type
    unsaved = true;
});

将以上代码添加到您的alert_unsaved_changes.js文件中。

希望这可以帮助。


您可以尝试添加alert('asd');吗?未保存之前= true; 然后提醒(未保存);因此,您将了解更改数据时未保存的内容。
AlphaMale 2012年

是的,它只是一个javascript。你包括jQuery吗?
AlphaMale 2012年

是的..我已经包含了jquery ...我刚刚在萤火虫中检查了..我得到了错误,因为“未定义$”。 -1.4.1-vsdoc.js“> </ script>在母版页和其他页面中也是如此
user1181942 2012年

1
如果您单击“保存”按钮,是否有办法使此选项不运行
Jon Harding

1
这很棒。效果很好,但是您能告诉我为什么它在iPhone上不起作用吗?我们必须使用其他功能吗?
stueynet 2014年

17

使用以下形式的序列化的版本:

准备好dom后执行以下代码:

// Store form state at page load
var initial_form_state = $('#myform').serialize();

// Store form state after form submit
$('#myform').submit(function(){
  initial_form_state = $('#myform').serialize();
});

// Check form changes before leaving the page and warn user if needed
$(window).bind('beforeunload', function(e) {
  var form_state = $('#myform').serialize();
  if(initial_form_state != form_state){
    var message = "You have unsaved changes on this page. Do you want to leave this page and discard your changes or stay on this page?";
    e.returnValue = message; // Cross-browser compatibility (src: MDN)
    return message;
  }
});

如果用户更改字段然后手动回滚,则不会显示警告


2
这是与更复杂的自定义用户控件一起使用的控件。我自己也采取了这种方法:)
Bernoulli IT

2

更改一旦用户因输入内容而不是输入的每个字符而变得模糊时,将触发事件。

如果你需要它被称为每次有变化时(即使焦点仍然是在输入字段),你将不得不依靠组合KEYUP和一堆事件的跟踪粘贴/只用鼠标cuting的。

PS我希望您知道,检测变化的方法不是最好的方法?如果用户输入了一些文本,请离开该字段,然后恢复所做的更改,脚本仍将向他发出有关已修改文本的警报。


2

如果您用文本框表示文本区域,则不仅应为输入而且还要为文本区域注册事件。您可以为isChange使用keyup,这样就不必等待用户从该区域模糊。

$("input[type='text'], textarea").keyup(function () {
    isChange = true;
})

1

为什么不简单地将事件绑定到change回调?

$(":input").change(function()
{
    $(window).unbind('unload').bind('unload',function()
    {
        alert('unsaved changes on the page');
    });
});

另外,您可以使用confirm并选择触发更改事件的最后一个元素:

$(":input").change(function()
{
    $(window).unbind('unload').bind('unload',(function(elem)
    {//elem holds reference to changed element
        return function(e)
        {//get the event object:
            e = e || window.event;
            if (confirm('unsaved changes on the page\nDo you wish to save them first?'))
            {
                elem.focus();//select element
                return false;//in jQuery this stops the event from completeing
            }
        }
    }($(this)));//passed elem here, I passed it as a jQ object, so elem.focus() works
    //pass it as <this>, then you'll have to do $(elem).focus(); or write pure JS
});

如果您有一些保存按钮,请确保取消绑定卸载事件,但是:

$('#save').click(function()
{
    $(window).unbind('unload');
    //rest of your code here
});

1

这确实是@AlphaMale答案的不同版本,但在一些方面有所改进:

# Message displayed to user. Depending on browser and if it is a turbolink,
# regular link or user-driven navigation this may or may not display.
msg = "This page is asking you to confirm that you want to leave - data you have entered may not be saved."

# Default state
unsaved = false

# Mark the page as having unsaved content
$(document).on 'change', 'form[method=post]:not([data-remote]) :input', -> unsaved = true

# A new page was loaded via Turbolinks, reset state
$(document).on 'page:change', -> setTimeout (-> unsaved = false), 10

# The user submitted the form (to save) so no need to ask them.
$(document).on 'submit', 'form[method=post]', ->
  unsaved = false
  return

# Confirm with user if they try to go elsewhere
$(window).bind 'beforeunload', -> return msg if unsaved

# If page about to change via Turbolinks also confirm with user
$(document).on 'page:before-change', (event) ->
  event.preventDefault() if unsaved && !confirm msg

这可以通过以下方式更好:

  • 是IMHO自动将其改进的coffeescript。:)
  • 它完全基于事件冒泡,因此会自动处理动态内容(@AlphaMale的更新也有此内容)。
  • 它仅在POST表单上运行,因为GET表单没有我们通常想要避免丢失的数据(即GET表单往往是搜索框和过滤条件)。
  • 无需绑定到特定按钮即可执行保存。无论何时提交表单,我们都认为提交已保存。
  • 它与Turbolinks兼容。如果不需要,只需删除两个page:事件绑定即可。
  • 它的设计使您可以将其仅包含在其余的JS中,并且整个站点都将受到保护。

0

我使用$('form').changeetc.函数来设置脏位变量。不适合捕获所有更改(按照之前的答案),但是可以在我的应用程序中捕获我感兴趣的所有内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.