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

t3psigkw  于 2023-04-20  发布在  jQuery
关注(0)|答案(9)|浏览(185)

我有一个选项卡式的html表单,在从一个选项卡导航到另一个选项卡时,当前选项卡的数据被持久化(在DB上),即使数据没有变化。
我想只有在编辑表单时才进行持久性调用。表单可以包含任何类型的控件。不需要通过键入一些文本来弄脏表单,但在日历控件中选择日期也符合条件。
实现此目的的一种方法是在默认情况下以只读模式显示表单,并具有“编辑”按钮,如果用户单击编辑按钮,则调用DB(再次,无论数据是否被修改。这是对当前现有内容的更好改进)。
我想知道如何写一个通用的JavaScript函数,将检查是否有任何控件的值已被修改?

uyhoqukh

uyhoqukh1#

在纯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()) {
   // ...
}
mwg9r5ms

mwg9r5ms2#

我不确定我是否理解了你的问题,但是addEventListener呢?如果你不太关心IE8的支持,这应该没问题。下面的代码对我来说是有效的:

var form = document.getElementById("myForm");

form.addEventListener("input", function () {
    console.log("Form has changed!");
});
flvlnr44

flvlnr443#

如果JQuery是不可能的。在Google上快速搜索发现MD5和SHA1哈希算法的Javascript实现。如果你愿意,你可以连接所有表单输入并对其进行哈希,然后将该值存储在内存中。当用户完成时。连接所有值并再次哈希。比较2个哈希。如果它们相同,则用户没有更改任何表单字段。如果它们不同,则用户可以将其保存在内存中。有些东西被编辑了,你需要调用你的持久性代码。

gzszwxb4

gzszwxb44#

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

$(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>
smtd7mpg

smtd7mpg5#

表单更改可以在没有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;
}
83qze16e

83qze16e6#

下面是我如何做到的(不使用jQuery)。
在我的例子中,我希望一个特定的表单元素不被计算在内,因为它是触发检查的元素,因此总是会发生变化。异常元素名为'reporting_period',并硬编码在函数'hasFormChanged()'中。
要进行测试,请让一个元素调用函数“changeReportingPeriod()”,您可能希望将其命名为其他名称。
重要提示:当值被设置为它们的原始值时(通常在页面加载时,但在我的情况下不是这样),必须调用setInitialValues()。
注意事项:我并不认为这是一个优雅的解决方案,事实上我并不相信优雅的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());
    }
e4yzc0pl

e4yzc0pl7#

下面是原生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>
stszievb

stszievb8#

我真的很喜欢上面Teekin的贡献,并实现了它。
然而,我已经扩展了它,允许复选框也使用这样的代码:

// Gets all form elements from the entire document.
function getAllFormElements() {
    // Return variable.
    var all_form_elements = Array();

    // The form.
    var Form = document.getElementById('frmCompDetls');

    // Different types of form elements.
    var inputs = Form.getElementsByTagName('input');
    var textareas = Form.getElementsByTagName('textarea');
    var selects = Form.getElementsByTagName('select');
    var checkboxes = Form.getElementsByTagName('CheckBox');

    // 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]);
    }
    for (i = 0; i < checkboxes.length; i++) {
        all_form_elements.push(checkboxes[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++) {
        if(inputs[i].type != "checkbox"){
            initial_values.push(inputs[i].value);
        }
        else
        {
            initial_values.push(inputs[i].checked);
        }
    }
    
}

function hasFormChanged() {
    var has_changed = false;
    var elements = getAllFormElements();
    var diffstring = ""
    for (var i = 0; i < elements.length; i++) {
        if (elements[i].type != "checkbox"){
            if (elements[i].value != initial_values[i]) {
                has_changed = true;
                //diffstring = diffstring + elements[i].value+" Was "+initial_values[i]+"\n";
                break;
            }
         }
         else
         {
            if (elements[i].checked != initial_values[i]) {
                has_changed = true;
                //diffstring = diffstring + elements[i].value+" Was "+initial_values[i]+"\n";
                break;
            }
         }
    }
    //alert(diffstring);
    return has_changed;
}

diffstring只是一个调试工具

4c8rllxm

4c8rllxm9#

这里是Philippe Leybaert’s answer,所有字段包括selecttextareainput以及纯JavaScript中的serializesolution from @nikoskip
它检查值是否真的被更改,而不是恢复到原始状态。

var $ = function( query ) { return document.querySelector( query ) }

HTMLFormElement.prototype.trackChanges = function(){
    let data = new URLSearchParams(new FormData(this)).toString();
    this.dataset.origData = data;
}

HTMLFormElement.prototype.isChanged = function(){
    let data = new URLSearchParams(new FormData(this)).toString();
    return ( data != this.dataset.origData )
}

然后你可以简单地说:

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

并检查表单是否已更改:

if ($("#myform").isChanged()) {
   // ...
}

示例:

var $ = function( query ) { return document.querySelector( query ) }

HTMLFormElement.prototype.trackChanges = function(){
  let data = new URLSearchParams(new FormData(this)).toString();
  this.dataset.origData = data;
}

HTMLFormElement.prototype.isChanged = function(){
  let data = new URLSearchParams(new FormData(this)).toString();
  return ( data != this.dataset.origData )
}

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

function TestForm(){
  if( $("#myform").isChanged())
    alert("Form has changed");
  else
    alert("Form has not changed");
  return false;
}
* { font: 16pt Arial }

div { margin: 20px 0 }
<form action="" method="get" id="myform" onsubmit="return TestForm()">
  <div>
    <label>Date:
      <input type="date" name="date">
    </label>
  </div>
  <div>
    <label>Email: 
      <input type="email" name="email">
    </label>
  </div>
  <div>
    <button>Is form changed?</button>
  </div>
 </form>

相关问题