Статьи

Как написать универсальную функцию обнаружения обновления формы в JavaScript

В моем последнем посте мы узнали, как проверить, были ли изменены отдельные элементы формы пользователем. Сегодня мы будем использовать эту информацию для написания кода JavaScript, который может обнаруживать обновления в любой форме.

Вот примеры и ссылки на код:

Наши предпосылки

Поскольку мы все хорошие разработчики, мы определим наши требования перед тем, как вырезать любой код:

  • Мы напишем функцию FormChanges (), которая принимает один перегруженный аргумент формы — либо узел DOM формы, либо идентификатор строки.
  • Функция вернет массив узлов элемента формы, которые пользователь изменил. Это позволяет нам определить, какие поля были изменены или, если массив пуст, то никакие поля не изменились.
  • Функция вернет NULL, если форма не найдена.
  • Мы не будем зависеть от какой-либо конкретной библиотеки JavaScript, поэтому функция остается совместимой со всеми из них.
  • Он должен работать во всех современных браузерах — и IE6 или IE7.

Функция FormChanges ()

Чтобы облегчить вам жизнь, вот начало нашей функции:

function FormChanges(form) { 

Мы перегружаем аргумент формы — это может быть элемент DOM, но, если это строка идентификатора, нам нужно найти этот элемент в DOM:

 if (typeof form == "string") form = document.getElementById(form); 

Если у нас нет узла формы, функция вернет ноль без дальнейшей работы:

 if (!form || !form.nodeName || form.nodeName.toLowerCase() != "form") return null; 

Теперь мы объявим переменные, которые будем использовать в функции:

  • «Изменено» — это возвращенный массив элементов формы, которые были обновлены пользователем.
  • ‘n’ — это узел элемента формы
  • ‘c’ устанавливается в true, если элемент был изменен
  • ‘def’ — опция по умолчанию для блоков выбора
  • «o», «ol» и «opt» — временные переменные, используемые в циклах
 var changed = [], n, c, def, o, ol, opt; 

Теперь мы можем запустить наш основной цикл, который проверяет каждый элемент формы по очереди. Первоначально для параметра c установлено значение false, указывающее, что в проверяемом элементе не было никаких изменений:

 for (var e = 0, el = form.elements.length; e < el; e++) { n = form.elements[e]; c = false; 

Далее мы извлечем имя узла (input, textarea, select) и рассмотрим его в операторе switch. Мы ищем только узлы select и not-select, поэтому оператор switch не является строго обязательным. Тем не менее, он легче для чтения и позволяет нам добавлять дополнительные типы узлов при их представлении.

Обратите внимание, что большинство браузеров возвращают имя узла в верхнем регистре, но мы играем его безопасно и всегда конвертируем строку в нижний регистр.

 switch (n.nodeName.toLowerCase()) { 

Первый оператор case оценивает выпадающие списки. Это самая сложная проверка, так как мы должны пройти через все дочерние элементы option чтобы сравнить свойства selected и defaultSelected.

Цикл также устанавливает def для последней опции с атрибутом selected. Если у нас есть блок с одним выбором, тогда def сравнивается со свойством selectedIndex этого узла, чтобы убедиться, что мы обрабатываем ситуации, когда ни у одного option или у нескольких элементов option нет атрибута selected ( полное объяснение см. В предыдущей статье). ).

 // select boxes case "select": def = 0; for (o = 0, ol = n.options.length; o < ol; o++) { opt = n.options[o]; c = c || (opt.selected != opt.defaultSelected); if (opt.defaultSelected) def = o; } if (c && !n.multiple) c = (def != n.selectedIndex); break; 

Теперь нам нужно обработать элементы input и textarea . Обратите внимание, что наш case "textarea": не использует разрыв, поэтому он попадает в case "input": code.

Флажки и радиоэлементы имеют свои свойства selected и defaultChecked по сравнению, в то время как все другие типы имеют свое значение по сравнению с defaultValue

 // input / textarea case "textarea": case "input": switch (n.type.toLowerCase()) { case "checkbox": case "radio": // checkbox / radio c = (n.checked != n.defaultChecked); break; default: // standard values c = (n.value != n.defaultValue); break; } break; } 

Если значение c равно true, элемент изменился, поэтому мы добавляем его в измененный массив. Цикл завершен:

 if (c) changed.push(n); } 

Нам просто нужно вернуть измененный массив и завершить функцию:

 return changed; } 

Пример использования

Предположим, мы создали следующую форму:

 <form id="myform" action="index.html" method="post"> <fieldset> <legend>Your profile</legend> <input type="hidden" id="changed" name="changed" value="yes" /> <div> <label for="name">name:</label> <input type="text" id="name" name="name" value="Jonny Dough" /> </div> <div> <label for="job">job title:</label> <select id="job" name="job"> <option>web designer</option> <option selected="selected">web developer</option> <option>graphic artist</option> <option>IT professional</option> <option>other</option> </select> </div> <div> <button type="submit">Update Profile</button> </div> </fieldset> </form> 

Мы можем проверить, изменил ли пользователь какие-либо поля формы, используя такой код, как:

 var changed = FormChanges("myform"); alert(changed.length + " field(s) have been updated."); 

Или, если никаких изменений не произошло, мы можем изменить скрытое значение «изменено» на «нет» при отправке формы. Это позволило бы коду на стороне сервера пропускать проверку полей и обновления базы данных:

 var form = document.getElementById("myform"); form.onsubmit = function() { if (FormChanges(form).length == 0) { document.getElementById("changed").value = "no"; } return true; } 

(Примечание: изменение «да» на «нет» изящно ухудшается, поскольку, если JavaScript не доступен, сервер всегда будет обрабатывать входящие данные.)

Я надеюсь, что вы найдете это полезным.