Общий способ определить, редактируется ли html-форма
У меня есть HTML-форма с вкладками. При переходе с одной вкладки на другую данные текущей вкладки сохраняются (в БД), даже если данные не изменяются.
Я хотел бы сделать вызов персистентности только в том случае, если форма редактируется. Форма может содержать любой вид контроля. Загрязнение формы не обязательно должно быть путем ввода некоторого текста, но выбор даты в элементе управления календарем также будет квалифицироваться.
одним из способов достижения этого было бы отображение формы в режиме только для чтения по умолчанию и есть кнопка "Изменить", и если пользователь нажимает кнопку "изменить", то выполняется вызов БД (еще раз, независимо от того, изменяются ли данные. Это лучшее улучшение к тому, что в настоящее время существует).
Я хотел бы знать, как написать общую функцию javascript, которая будет проверять, было ли изменено какое-либо значение элемента управления ?
7 ответов:
в чистом javascript это было бы непростой задачей, но jQuery делает это очень легко сделать:
$("#myform :input").change(function() { $("#myform").data("changed",true); });
затем перед сохранением, вы можете проверить, если он был изменен:
if ($("#myform").data("changed")) { // submit the form }
в приведенном выше примере форма имеет идентификатор, равный "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()) { // ... }
в случае, если JQuery не может быть и речи. Быстрый поиск в Google нашел Javascript-реализации алгоритмов хэширования MD5 и SHA1. Если вы хотите, вы можете объединить все входные данные формы и хэшировать их, а затем сохранить это значение в памяти. Когда пользователь закончит. Объедините все значения и хэш снова. Сравните 2 хэша. Если они совпадают, пользователь не изменил ни одного поля формы. Если они разные, что-то было отредактировано, и вам нужно вызвать свою настойчивость код.
Я не уверен, что правильно понял ваш вопрос, но как насчет addEventListener? Если вы не слишком заботитесь о поддержке IE8, это должно быть хорошо. Следующий код работает для меня:
var form = document.getElementById("myForm"); form.addEventListener("input", function () { console.log("Form has changed!"); });
вот как я это сделал (без использования 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()); }
еще один способ добиться этого-сериализовать форму:
$(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 без jQuery:
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()
можно безопасно вызывать несколько раз на протяжении всего жизненного цикла вашей страницы: см. тест на JSBin
Для старых браузеров, которые не поддерживают новые функции arrow / array: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; }
вот демонстрация метода polyfill в собственном JavaScript, который использует
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>