我有一个标签式html表单。在从一个选项卡导航到另一个选项卡时,即使数据没有变化,当前选项卡的数据也会保留(在数据库上)。
我想仅在编辑表单时才进行持久性调用。表单可以包含任何类型的控件。不需要输入一些文本,但是在日历控件中选择日期也是合格的。
实现此目的的一种方法是默认情况下以只读模式显示表单并使用“编辑”按钮,如果用户单击编辑按钮,则会调用DB(再次,无论是否数据被修改。这是对现有数据的更好改进。
我想知道如何编写一个通用的javascript函数来检查是否有任何控件值被修改过?
答案 0 :(得分:134)
在纯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()) {
// ...
}
答案 1 :(得分:32)
如果JQuery不可能。在Google上快速搜索发现了MD5和SHA1哈希算法的Javascript实现。如果您愿意,可以连接所有表单输入并对其进行哈希处理,然后将该值存储在内存中。当用户完成时。连接所有值并再次哈希。比较2个哈希值。如果它们相同,则用户不会更改任何表单字段。如果它们不同,则会编辑某些内容,您需要调用持久性代码。
答案 2 :(得分:11)
我不确定我的问题是否正确,但是addEventListener呢?如果你不太关心IE8的支持,这应该没问题。以下代码对我有用:
var form = document.getElementById("myForm");
form.addEventListener("input", function () {
console.log("Form has changed!");
});
答案 3 :(得分:4)
这是我如何做到的(不使用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());
}
答案 4 :(得分:4)
另一种实现此目的的方法是序列化表单:
$(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>
答案 5 :(得分:3)
在没有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;
}
答案 6 :(得分:1)
我真的很喜欢上面 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 只是一个调试工具
答案 7 :(得分:0)
这是本机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')
}
})
&#13;
<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>
&#13;