Как дождаться, когда пользователь закончит вводить данные в input (на примере исправления бага)

Автор:
Андрей Гук — автор статьи Андрей Гук
#Советы

В этой статье мы пофиксим баг с отправкой ajax запроса (даже не запроса, а десятка запросов) на сервер, которые приводили к ошибке 500 и непредсказуемому получению данных.

Итак, классическое событие на получение данных, введенных в input с клавиатуры, выглядит так

See the Pen Untitled by ctr99ru (@ctr99ru) on CodePen.

Все просто. При "отпускании" клавиши событие срабатывает, ну и мы прописали, чтобы в этот момент данные отображались в заранее подготовленном параграфе.

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

Решение-костыль — поменять тип события

Есть события, которые происходят часто: нажатия клавиш, движения мышью. Если поменять их на тип change, это исправит ситуацию, потому что тогда данные будут передаваться, когда инпут потеряет фокус (пользователь уберет мышку, кликнет в другом месте). Но тут есть риск, что ухудшится пользовательский опыт. Да и поменять тип события можно не всегда.

Решение получше — отложить получение значения (на примере бага у одного из клиентов)

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

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

Как будем решать? Можно попробовать повесить простейший таймаут на ajax-запрос, но это не решит проблему, а просто отложит все запросы, то есть они все равно отправятся все, но с задержкой.

Но мысль с таймаутом правильная, только его нужно обнулять, если инпут получил новое значение.

Вот как выглядит моментальная передача значения (верхний ползунок) и отложенная (нижний ползунок).

See the Pen Range input delayed value by ctr99ru (@ctr99ru) on CodePen.

Чуть поясним нижний ползунок. Если вы попробовали его подергать, то заметили, что под ним не появляется значение до тех пор, пока вы не перестанете его дергать. Это сделано с помощью функции установки таймаута setTimeout().

  1. До события устанавливаем значение переменной таймера на null.
  2. Если происходит событие, обнуляем таймер с помощью функции отмены таймаута clearTimeout(), потому что он мог быть запущен предыдущим внесением изменений в инпут.
  3. Обнулив, сразу запускаем новый таймаут, установив нужную нам задержку (в нашем случае - 1 секунда).

Если "ползунок" перестали двигать, новых событий не будет, то есть выполнится код внутри таймера. В нашем случае - просто показываем значение инпута на экране. В случае с формой клиента - отправляем не 30 почти одновременных ajax-запросов и заваливаем сервер, а 1 раз в секунду.