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

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

我只想在编辑表单时进行持久性调用。 表单可以包含任何types的控件。 炫耀表单不一定要通过input一些文本,但在日历控件中select一个date也是合格的。

实现这一目的的一种方式是默认情况下以只读模式显示表单并具有“编辑”button,如果用户单击编辑button,则对DB进行调用(再一次,不pipe数据是否被修改这是对现有的更好的改进)。

我想知道如何编写一个通用的JavaScript函数,检查是否有任何控件值已被修改?

在纯JavaScript中,这不是一件容易的事情,但jQuery使它非常容易:

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

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

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

在上面的例子中,表单的id等于“myform”。

如果你需要多种forms,你可以很容易地把它变成一个插件:

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

那么你可以简单地说:

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

并检查表单是否发生了变化:

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

如果jQuery是不可能的。 在Google上快速search,发现了MD5和SHA1哈希algorithm的Javascript实现。 如果你想要的话,你可以连接所有的表单input并对它们进行散列,然后将该值存储在内存中。 当用户完成。 连接所有的值并再次散列。 比较2个哈希。 如果他们是相同的,用户不会更改任何表单域。 如果它们不同,则编辑了一些东西,并且需要调用持久性代码。

这是我做的(不使用jQuery)。

在我的情况下,我想要一个特定的表单元素不被计数,因为它是触发检查的元素,所以总是会改变。 exception元素被命名为“reporting_period”,并在函数hasFormChanged()中进行硬编码。

为了testing,使一个元素调用函数“changeReportingPeriod()”,你可能想要命名别的东西。

重要说明:当值已经被设置为其原始值(通常在页面加载时,但在我的情况下)时,必须调用setInitialValues()。

注:我不认为这是一个优雅的解决scheme,实际上我不相信优雅的JavaScript解决scheme。 我个人在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()); } 

我不知道如果我的问题正确,但addEventListener呢? 如果你不太在意IE8的支持,这应该没问题。 以下代码正在为我工​​作:

 var form = document.getElementById("myForm"); form.addEventListener("input", function () { console.log("Form has changed!"); }); 

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

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

以下是本地JavaScript中的一个polyfill方法演示,它使用FormData() API检测创build,更新和删除的表单条目。 您可以使用HTMLFormElement#isChanged检查是否有任何更改,并使用HTMLFormElement#changes (假设它们未被input名称掩盖)获取包含重置表单差异的对象:

 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>