【问题标题】:What is the easiest way to detect if at least one field has been changed on an HTML form?检测 HTML 表单上是否至少有一个字段已更改的最简单方法是什么?
【发布时间】:2020-05-19 16:42:38
【问题描述】:

我有一个包含 20 多个字段的 HTML 表单。我在页面上还有几个链接将引导用户离开表单...可能没有保存任何更改。

如果任何表单字段已更改,我想警告(JS 确认)这些链接的用户 onClick,但我不想创建一个巨大的 switch 语句,然后我需要在添加新字段时维护它表格。我知道如何在 Javascript 中创建一长串“if”语句,命名每个字段并检查每个值,但如果我能侥幸逃脱,我不想这样做。

检查用户是否更改了至少一个字段值的最简单方法是什么?

【问题讨论】:

    标签: javascript html


    【解决方案1】:

    接近

    1. 在显示之前对表单(及其所有值)进行序列化(jQuery wayPrototype way
    2. "onbeforeunload" 事件处理程序中再次对其进行序列化

    如果两者不匹配,那么他们一定是更改了表单,所以从您的onbeforeunload 处理程序返回一个字符串(例如“您有未保存的数据”)。

    此方法允许表单字段在“更改确认”逻辑保持不变的情况下演变。

    示例 (混合 javascript 和 jquery)

    var form_clean;
    
    // serialize clean form
    $(function() { 
        form_clean = $("form").serialize();  
    });
    
    // compare clean and dirty form before leaving
    window.onbeforeunload = function (e) {
        var form_dirty = $("form").serialize();
        if(form_clean != form_dirty) {
            return 'There is unsaved form data.';
        }
    };
    

    【讨论】:

    • 噢,这真是个好主意。不错。
    • 2014 年,这仍然是最佳做法吗?
    • 第一行不只是var form_clean = $("form").serialize();有什么原因吗?
    • 这将如何与动态添加的 html 元素一起工作?似乎您必须随时注意操作更改 DOM 并重新调用 serialize 方法。此外,这如何与诸如敲除和角度之类的库一起使用,您甚至不必在表单中包含表单值?
    【解决方案2】:

    我很确定这是个坏主意,但我想把它扔掉。

    表单字段有一种方法可以获取“默认值”(即该字段在加载时的值),您可以将其与当前值进行比较。如果您将字段添加到表单,则对所有字段进行简单循环就无需维护。

    可能存在也可能不存在与“默认值”属性相关的各种浏览器错误,因此如果没有进行广泛的测试,我不会相信这种方法。下面的代码是概念证明,(我)没有在任何实际应用程序中使用。

    function IsDirty(form) {
        for (var i=0; i<form.elements.length; i++) {
            var field = form.elements[i];
            switch (field.type) {
                case "select-multiple":
                case "select-one":
                    var options = field.options;
                    for (var j=0; j<options.length; j++) {
                        if(options[j].selected != options[j].defaultSelected) return true;
                    }
                    break;
                case "text":
                case "file":
                case "password":
                    if (field.value != field.defaultValue) return true;
                    break;
                case "checkbox":
                case "radio":
                    if (field.checked != field.defaultChecked) return true;
                    break;
            }
        }
        return false;
    }
    

    【讨论】:

    • 据我所知,这是唯一的方法。它可以防止在刷新后保留新的表单值,例如 Firefox。
    【解决方案3】:

    使用 jQuery 这很容易。您也应该能够使用相同的前提在 vanilla javascript 中实现相同的结果。

    var $inps = $('#myForm').find('input,select,textarea')
      , formAltered = false
    ;
    $inps.change(function() {
        formAltered = true;
        $inps.unbind('change'); // saves this function running every time.
    });
    

    唯一的问题是,如果您更改了一个值,然后将其更改回原来的值,它仍会报告表单已更改。

    【讨论】:

    • +1,您可以详细说明以消除数据没有真正改变的情况 - 您可以保存初始状态并与之进行比较(为此使用 onfocus 事件),然后才将表单设置为“脏”
    • 你可以把第一行做得更好:var $inps = $('#myForm :input'), formAltered = false;
    【解决方案4】:

    这是一个可以添加到表单中的单行:

    $(':input',document.myForm).bind("change", function() { 
      enablePrompt(true); }); // Prevent accidental navigation away
    

    然后您可以为整个站点创建 enableUnloadPrompt() 函数:

    function enablePrompt(enabled) {
      window.onbeforeunload = enabled ? "Your changes are not saved!" : null;
    }
    

    最后,在正确提交表单之前,请确保:

    enablePrompt(false);
    

    这不会检查表单的值是否不同,只有当表单被用户更改过时。但是,它简单易用。

    【讨论】:

      【解决方案5】:

      这可以只用一个布尔变量来处理,我们称之为脏位处理。如果您观察到,通常在网页中,一旦用户对任何字段执行某些编辑操作,表单就会被视为脏(已编辑)(即使数据在编辑后保持不变)。当用户尝试离开页面时,系统会提示用户是否要保存更改。

      根据标准做法,在编辑某些字段后,不检查值是否实际更改。例如:如果用户编辑并将“xyz”附加到文本字段,然后删除“xyz”,则表单数据基本上保持与以前相同,但表单仍被视为“脏”,并且当用户收到警告消息时会提示他试图离开。

      所以,如果你想实现这个,事情变得非常简单。您只需将 onchange() 事件处理程序添加到控件,并在这些事件处理程序中将诸如 isDirty 之类的全局布尔变量设置为 true。

      一旦用户想要离开,您可以闪烁一条消息“当前页面上可能有未保存的更改。您要保存吗?”。即使用户注意到他的编辑没有改变初始数据,他也不会失望。

      上面给出的答案实现了这种行为。我写这个是因为你似乎有一个想法来检查每个字段的初始值,看看它在编辑后是否真的被改变了。只是想告诉你根本不需要检查每个字段。

      【讨论】:

        【解决方案6】:

        就我而言,我结合了@Crescent Fresh 和@nickf 的答案并得到了这个:

        var formBefore;
        
        var $inps = $('form').find('input,select,textarea');
        
        $(function() {
            formBefore = $("form").serialize();
        });
        
        $inps.change(function () {
            var changedForm = $("form").serialize();
            if (formBefore != changedForm) {
                $("#btnSave").css('background-color', 'green');
            } else {
                $("#btnSave").css('background-color', '');
            }
        });
        

        【讨论】:

          【解决方案7】:

          多年来,早先发布的答案已经证明了自己(经过一些小的改进)。这是我在 onBeforeUnload 事件函数中使用的函数。

          /*
          ** Determines if a form is dirty by comparing the current
          ** value of each element with its default value.
          **
          ** @param {Form} form the form to be checked.
          ** @return {Boolean} true if the form is dirty, false otherwise.
          */
          function formIsDirty(form) {
              for (var i = 0; i < form.elements.length; i++) {
                  var element = form.elements[i];
                  var type = element.type;
                  switch (element.type) {
                  case "checkbox":
                  case "radio":
                      if (element.checked != element.defaultChecked)
                          return true;
                      break;
                  case "number":
                  case "hidden":
                  case "password":
                  case "date":
                  case "text":
                  case "textarea":
                      if (element.value != element.defaultValue)
                          return true;
                      break;
                  case "select-one":
                  case "select-multiple":
                      for (var j = 0; j < element.options.length; j++)
                          if (element.options[j].selected != element.options[j].defaultSelected)
                              return true;
                      break;
                  }
              }
              return false;
          }
          

          以下是 onBeforeUnload 处理函数的示例:

              function onBeforeUnload(event) {
                  event = event || window.event;
                  for (i = 0; i < document.forms.length; i++) {
                      switch (document.forms[i].id) {
                      case "search":
                          break;
                      default:
                          if (formIsDirty(document.forms[i])) {
                              if (event)
                                  event.returnValue = "You have unsaved changes.";
                              return "You have unsaved changes.";
                          }
                          break;
                      }
                  }
              }
          

          【讨论】:

            猜你喜欢
            • 2020-03-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-09-24
            • 1970-01-01
            • 2011-09-26
            • 1970-01-01
            相关资源
            最近更新 更多