Уже неоднократно на хабре (вот в этой публикации и в этой) ставился вопрос о том, что было бы хорошо кнопкам формы, отправляемой на сервер, ставить свойство
Однако, до сих пор так и не разобрались, зачем это нужно и как все-таки это делать. Казалось бы, что может быть проще и о чем здесь вообще можно разговаривать, ан нет — на поверку все оказалось не так тривиально. Сразу замечу, что нижеследующие рассуждения применимы к обеим типам форм: как отправляемым через обычный 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>