Уже неоднократно на хабре (вот в этой публикации и в этой) ставился вопрос о том, что было бы хорошо кнопкам формы, отправляемой на сервер, ставить свойство
Однако, до сих пор так и не разобрались, зачем это нужно и как все-таки это делать. Казалось бы, что может быть проще и о чем здесь вообще можно разговаривать, ан нет — на поверку все оказалось не так тривиально. Сразу замечу, что нижеследующие рассуждения применимы к обеим типам форм: как отправляемым через обычный SUBMIT, так и с помощью AJAX.
Понятно также, что лишние запросы можно предотвратить, повесив на форму какой-нибудь
Почему недостаточно просто делать нажатую кнопку неактивной:
Вкратце сценарий таков.
disabled = "disabled"
.Однако, до сих пор так и не разобрались, зачем это нужно и как все-таки это делать. Казалось бы, что может быть проще и о чем здесь вообще можно разговаривать, ан нет — на поверку все оказалось не так тривиально. Сразу замечу, что нижеследующие рассуждения применимы к обеим типам форм: как отправляемым через обычный SUBMIT, так и с помощью AJAX.
Зачем нужно делать кнопки неактивными
- Чтобы пользователю стало очевидным, что он уже нажал на кнопку, и что форма отправляется
- Чтобы сервер не загружался лишними запросами, и чтобы уменьшить вероятность какой-либо ошибки
Понятно также, что лишние запросы можно предотвратить, повесив на форму какой-нибудь
class="form_is_loading"
, и при всяком сабмите проверять на наличие этого класса. Но зачем делать эти проверки, когда можно обойтись без них, просто сделав кнопку неактивной?Как делать кнопки неактивными
<input type="submit" onclick="this.disabled=true;">Этот предложенный в вышеупомянутых топиках простой вариант оказывается недостаточным и неработоспособным.
Почему недостаточно просто делать нажатую кнопку неактивной:
- Submit формы может произойти и по нажатию на Enter. Поэтому обработку кнопок надо вешать на событие onsubmit самой формы. К тому же, у формы может быть несколько кнопок, и было бы логичным делать их все неактивными, а не только ту кнопку, которую нажали.
- Если после сабмита формы вновь вернуться на страницу с формой (по кнопке «Назад» в браузере), то сработает кеширование: мы столкнемся с неактивными кнопками и не сможем отправить форму еще раз — без принудительной перезагрузки страницы с потерей всех заполненных ранее полей (Возврат к поисковой форме со страницы результатов поиска тут живейший пример).
- Если у формы несколько кнопок (например, «Опубликовать» и «Отмена»), то мы не сможем передать серверу, какая именно кнопка была нажата: неактивная кнопка не передает свое имя и значение — даже если мы делаем ее неактивной по событию onsubmit
Вкратце сценарий таков.
- Кнопки делаем неактивными по событию onsubmit формы
- Кнопки возвращаем в активное состояние до ухода со страницы по событию window.onunload
- Каждая кнопка формы по событию onclick должна создавать одноименное hidden поле, через которое передаст свое значение серверу
//// html файл ////////////////////////////////////////////////////////////////////// <form id="the_form"> <input type="submit" name="send" value="Опубликовать"> <input type="submit" name="cancel" value="Отменить"> </form> <script> formUploader.prepareForm(document.getElementById('the_form')); </script> //// js файл //////////////////////////////////////////////////////////////////////// <script> formUploader = { prepareForm: function(form){ // Каждая значимая кнопка формы при клике должна создать одноименное hidden поле, // чтобы на сервер передалась информация о том, какая кнопка была кликнута var allFormFields = form.getElementsByTagName('input'); for (var i=0; i<allFormFields.length; i++){ if(allFormFields[i].type == 'submit' && allFormFields[i].name){ allFormFields[i].onclick = function(){ formUploader.createHiddenField(this); } } } // Визуализируем форму как отправляемую на сервер на событии onsubmit // (в т.ч. делаем все кнопки неактивными) form.onsubmit = function(){ formUploader.setFormLoading(form); } // Очищаем визуализацию формы (в т.ч. делаем все кнопки вновь активными) // при уходе со страницы - по глобальному событию onunload window.onunload = function(){ formUploader.clearFormLoading(form) } }, setFormLoading: function(form){ // Создаем визуализацию загрузки формы и делаем все кнопки неактивными // disabled=true; }, clearFormLoading: function(form){ // Очищаем форму от визуализации загрузки и возвращаем кнопки в активное состояние // disabled=false; }, createHiddenField: function(button){ var input = document.createElement('input'); input.type = 'hidden'; input.name = button.name; input.value = button.value; button.parentNode.insertBefore(input, button); } } </script>