代码之家  ›  专栏  ›  技术社区  ›  Sathya

检测HTML表单是否被编辑的通用方法

  •  69
  • Sathya  · 技术社区  · 17 年前

    我有一个标签式HTML表单。在从一个选项卡导航到另一个选项卡时,即使数据没有更改,当前选项卡的数据也会被持久化(在数据库上)。

    我只想在编辑表单时进行持久性调用。表单可以包含任何类型的控件。弄脏表单不需要通过键入一些文本,但在日历控件中选择一个日期也符合条件。

    实现这一点的一种方法是默认情况下以只读模式显示表单,并具有“编辑”按钮,如果用户单击“编辑”按钮,则会调用db(再次调用,无论是否修改数据)。这是对目前存在的改进)。

    我想知道如何编写一个通用的javascript函数来检查是否修改了任何控件值?

    7 回复  |  直到 8 年前
        1
  •  128
  •   erlingormar    13 年前

    在纯JavaScript中,这不是一个简单的任务,但jQuery使其非常容易做到:

    $("#myform :input").change(function() {
       $("#myform").data("changed",true);
    });
    

    然后在保存之前,您可以检查它是否被更改:

    if ($("#myform").data("changed")) {
       // submit the form
    }
    

    在上面的示例中,表单的ID等于“myform”。

    如果您在许多形式中需要它,您可以很容易地将其转换为插件:

    $.fn.extend({
     trackChanges: function() {
       $(":input",this).change(function() {
          $(this.form).data("changed", true);
       });
     }
     ,
     isChanged: function() { 
       return this.data("changed"); 
     }
    });
    

    然后你可以简单地说:

    $("#myform").trackChanges();
    

    并检查表单是否已更改:

    if ($("#myform").isChanged()) {
       // ...
    }
    
        2
  •  32
  •   Matthew Vines    17 年前

    如果jquery是不可能的。在谷歌上的一个快速搜索发现了MD5和SHA1哈希算法的javascript实现。如果需要,可以连接所有表单输入并散列它们,然后将该值存储在内存中。当用户完成后。再次连接所有值和哈希。比较两个哈希值。如果它们相同,则用户不会更改任何表单字段。如果它们是不同的,则某些内容已被编辑,您需要调用持久性代码。

        3
  •  9
  •   mecograph Sid T    10 年前

    我不确定你的问题是否正确,但是AddEventListener呢?如果你不太在乎IE8的支持,这应该是好的。以下代码对我有效:

    var form = document.getElementById("myForm");
    
    form.addEventListener("input", function () {
        console.log("Form has changed!");
    });
    
        4
  •  4
  •   Teekin    16 年前

    以下是我如何做到的(不使用jquery)。

    在我的例子中,我希望一个特定的表单元素不被计算在内,因为触发检查的是这个元素,所以总是会发生变化。异常元素名为“reporting_period”,并在函数“hasformChanged()”中硬编码。

    要进行测试,请使元素调用函数“changeReportingPeriod()”,您可能需要将其命名为其他名称。

    重要提示:当值设置为其原始值时(通常在页面加载时,但在我的情况下不是这样),必须调用setInitialValues()。

    注意:我并不认为这是一个优雅的解决方案,事实上我不相信优雅的JavaScript解决方案。我个人在javascript中的重点是可读性,而不是结构上的优雅(好像在javascript中是可能的)。在编写javascript时,我根本不关心文件大小,因为这就是gzip的目的,并且试图编写更紧凑的javascript代码总是会导致无法忍受的维护问题。我不会道歉,也不会后悔,也不会拒绝辩论。它是javascript。对不起,我必须把这一点说清楚,以便说服自己,我应该费心发帖。快乐吧!:)

    
        var initial_values = new Array();
    
        // Gets all form elements from the entire document.
        function getAllFormElements() {
            // Return variable.
            var all_form_elements = Array();
    
            // The form.
            var form_activity_report = document.getElementById('form_activity_report');
    
            // Different types of form elements.
            var inputs = form_activity_report.getElementsByTagName('input');
            var textareas = form_activity_report.getElementsByTagName('textarea');
            var selects = form_activity_report.getElementsByTagName('select');
    
            // We do it this way because we want to return an Array, not a NodeList.
            var i;
            for (i = 0; i < inputs.length; i++) {
                all_form_elements.push(inputs[i]);
            }
            for (i = 0; i < textareas.length; i++) {
                all_form_elements.push(textareas[i]);
            }
            for (i = 0; i < selects.length; i++) {
                all_form_elements.push(selects[i]);
            }
    
            return all_form_elements;
        }
    
        // Sets the initial values of every form element.
        function setInitialFormValues() {
            var inputs = getAllFormElements();
            for (var i = 0; i < inputs.length; i++) {
                initial_values.push(inputs[i].value);
            }
        }
    
        function hasFormChanged() {
            var has_changed = false;
            var elements = getAllFormElements();
    
            for (var i = 0; i < elements.length; i++) {
                if (elements[i].id != 'reporting_period' && elements[i].value != initial_values[i]) {
                    has_changed = true;
                    break;
                }
            }
    
            return has_changed;
        }
    
        function changeReportingPeriod() {
            alert(hasFormChanged());
        }
    
    
    
        5
  •  3
  •   nikoskip    9 年前

    实现这一点的另一种方法是序列化表单:

    $(function() {
        var $form = $('form');
        var initialState = $form.serialize();
        
        $form.submit(function (e) {
          if (initialState === $form.serialize()) {
            console.log('Form is unchanged!');
          } else {
            console.log('Form has changed!');
          }
          e.preventDefault();
        });
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <form>
    Field 1: <input type="text" name="field_1" value="My value 1"> <br>
    Field 2: <input type="text" name="field_2" value="My value 2"> <br>
    Check: <input type="checkbox" name="field_3" value="1"><br>
    <input type="submit">
    </form>
        6
  •  3
  •   anthumchris    8 年前

    无需jquery,就可以在本机javascript中轻松检测到表单更改:

    function initChangeDetection(form) {
      Array.from(form).forEach(el => el.dataset.origValue = el.value);
    }
    function formHasChanges(form) {
      return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value);
    }
    


    initChangeDetection() 可以在页面的整个生命周期中安全地多次调用: See Test on JSBin


    对于不支持较新箭头/数组函数的较旧浏览器:
    function initChangeDetection(form) {
      for (var i=0; i<form.length; i++) {
        var el = form[i];
        el.dataset.origValue = el.value;
      }
    }
    function formHasChanges(form) {
      for (var i=0; i<form.length; i++) {
        var el = form[i];
        if ('origValue' in el.dataset && el.dataset.origValue !== el.value) {
          return true;
        }
      }
      return false;
    }
    
        7
  •  0
  •   Patrick Roberts Benjamin Gruenbaum    9 年前

    下面是本机javascript中的polyfill方法演示,它使用 FormData() 用于检测已创建、已更新和已删除表单条目的API。您可以使用 HTMLFormElement#isChanged 并使用 HTMLFormElement#changes (假设它们没有被输入名称屏蔽):

    Object.defineProperties(HTMLFormElement.prototype, {
      isChanged: {
        configurable: true,
        get: function isChanged () {
          'use strict'
    
          var thisData = new FormData(this)
          var that = this.cloneNode(true)
    
          // avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
          HTMLFormElement.prototype.reset.call(that)
    
          var thatData = new FormData(that)
    
          const theseKeys = Array.from(thisData.keys())
          const thoseKeys = Array.from(thatData.keys())
    
          if (theseKeys.length !== thoseKeys.length) {
            return true
          }
    
          const allKeys = new Set(theseKeys.concat(thoseKeys))
    
          function unequal (value, index) {
            return value !== this[index]
          }
    
          for (const key of theseKeys) {
            const theseValues = thisData.getAll(key)
            const thoseValues = thatData.getAll(key)
    
            if (theseValues.length !== thoseValues.length) {
              return true
            }
    
            if (theseValues.some(unequal, thoseValues)) {
              return true
            }
          }
    
          return false
        }
      },
      changes: {
        configurable: true,
        get: function changes () {
          'use strict'
    
          var thisData = new FormData(this)
          var that = this.cloneNode(true)
    
          // avoid masking: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/reset
          HTMLFormElement.prototype.reset.call(that)
    
          var thatData = new FormData(that)
    
          const theseKeys = Array.from(thisData.keys())
          const thoseKeys = Array.from(thatData.keys())
    
          const created = new FormData()
          const deleted = new FormData()
          const updated = new FormData()
    
          const allKeys = new Set(theseKeys.concat(thoseKeys))
    
          function unequal (value, index) {
            return value !== this[index]
          }
    
          for (const key of allKeys) {
            const theseValues = thisData.getAll(key)
            const thoseValues = thatData.getAll(key)
    
            const createdValues = theseValues.slice(thoseValues.length)
            const deletedValues = thoseValues.slice(theseValues.length)
    
            const minLength = Math.min(theseValues.length, thoseValues.length)
    
            const updatedValues = theseValues.slice(0, minLength).filter(unequal, thoseValues)
    
            function append (value) {
              this.append(key, value)
            }
    
            createdValues.forEach(append, created)
            deletedValues.forEach(append, deleted)
            updatedValues.forEach(append, updated)
          }
    
          return {
            created: Array.from(created),
            deleted: Array.from(deleted),
            updated: Array.from(updated)
          }
        }
      }
    })
    
    document.querySelector('[value="Check"]').addEventListener('click', function () {
      if (this.form.isChanged) {
        console.log(this.form.changes)
      } else {
        console.log('unchanged')
      }
    })
    <form>
      <div>
        <label for="name">Text Input:</label>
        <input type="text" name="name" id="name" value="" tabindex="1" />
      </div>
    
      <div>
        <h4>Radio Button Choice</h4>
    
        <label for="radio-choice-1">Choice 1</label>
        <input type="radio" name="radio-choice-1" id="radio-choice-1" tabindex="2" value="choice-1" />
    
        <label for="radio-choice-2">Choice 2</label>
        <input type="radio" name="radio-choice-2" id="radio-choice-2" tabindex="3" value="choice-2" />
      </div>
    
      <div>
        <label for="select-choice">Select Dropdown Choice:</label>
        <select name="select-choice" id="select-choice">
          <option value="Choice 1">Choice 1</option>
          <option value="Choice 2">Choice 2</option>
          <option value="Choice 3">Choice 3</option>
        </select>
      </div>
    
      <div>
        <label for="textarea">Textarea:</label>
        <textarea cols="40" rows="8" name="textarea" id="textarea"></textarea>
      </div>
    
      <div>
        <label for="checkbox">Checkbox:</label>
        <input type="checkbox" name="checkbox" id="checkbox" />
      </div>
    
      <div>
        <input type="button" value="Check" />
      </div>
    </form>