Pull to refresh

Тонкости свойства disable у кнопок формы, отправляемой на сервер (Как делать кнопки неактивными)

Reading time3 min
Views69K
Уже неоднократно на хабре (вот в этой публикации и в этой) ставился вопрос о том, что было бы хорошо кнопкам формы, отправляемой на сервер, ставить свойство disabled = "disabled".

Однако, до сих пор так и не разобрались, зачем это нужно и как все-таки это делать. Казалось бы, что может быть проще и о чем здесь вообще можно разговаривать, ан нет — на поверку все оказалось не так тривиально. Сразу замечу, что нижеследующие рассуждения применимы к обеим типам форм: как отправляемым через обычный SUBMIT, так и с помощью AJAX.

Зачем нужно делать кнопки неактивными

  1. Чтобы пользователю стало очевидным, что он уже нажал на кнопку, и что форма отправляется
  2. Чтобы сервер не загружался лишними запросами, и чтобы уменьшить вероятность какой-либо ошибки
Понятно, что можно предотвратить лишние нажатия при помощи навешивания специальной визуализации, говорящей, что запрос принят и форма отправляется (простейший пример — показать какой-нибудь анимированный gif). Однако, кнопки-то при этом все равно останутся кликабельными, и самые нетерпеливые пользователи не применут воспользоваться такой возможностью. При этом, на эти дополнительные нажатия форма уже никак не сможет отреагировать (анимированный gif уже крутится), и фрустрация пользователя только увеличится.

Понятно также, что лишние запросы можно предотвратить, повесив на форму какой-нибудь class="form_is_loading", и при всяком сабмите проверять на наличие этого класса. Но зачем делать эти проверки, когда можно обойтись без них, просто сделав кнопку неактивной?

Как делать кнопки неактивными


<input type="submit" onclick="this.disabled=true;">
Этот предложенный в вышеупомянутых топиках простой вариант оказывается недостаточным и неработоспособным.

Почему недостаточно просто делать нажатую кнопку неактивной:
  1. Submit формы может произойти и по нажатию на Enter. Поэтому обработку кнопок надо вешать на событие onsubmit самой формы. К тому же, у формы может быть несколько кнопок, и было бы логичным делать их все неактивными, а не только ту кнопку, которую нажали.
  2. Если после сабмита формы вновь вернуться на страницу с формой (по кнопке «Назад» в браузере), то сработает кеширование: мы столкнемся с неактивными кнопками и не сможем отправить форму еще раз — без принудительной перезагрузки страницы с потерей всех заполненных ранее полей (Возврат к поисковой форме со страницы результатов поиска тут живейший пример).
  3. Если у формы несколько кнопок (например, «Опубликовать» и «Отмена»), то мы не сможем передать серверу, какая именно кнопка была нажата: неактивная кнопка не передает свое имя и значение — даже если мы делаем ее неактивной по событию onsubmit
Итак, сценарий создания неактивных кнопок

Вкратце сценарий таков.
  1. Кнопки делаем неактивными по событию onsubmit формы
  2. Кнопки возвращаем в активное состояние до ухода со страницы по событию window.onunload
  3. Каждая кнопка формы по событию 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>
Tags:
Hubs:
+55
Comments38

Articles