Статьи

Автозаполнение форм с помощью jQuery и API веб-хранилища

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

В этой статье я покажу вам, как воссоздать то же улучшение, используя jQuery , jQuery.deserialize и API-интерфейс веб-хранилища .

Требования

Чтобы улучшить форму, о которой я упоминал во введении, мы решили показать список ранее выполненных поисков, до 20. Поиски сохраняются в браузере с помощью API-интерфейса веб-хранилища. Если у вас есть система входа в систему, вы можете изменить демо так, чтобы результаты поиска сохранялись в базе данных. В моем случае это не вариант, так как не было системы входа в систему.

Каждый элемент списка состоит из текста, представляющего значение, которое пользователь написал в главном поле, и подсписка, показывающего название поля и значение (я), записанные или выбранные (в случае флажков и переключателей). Когда пользователь щелкает один из этих поисков, поля формы автоматически заполняются значениями этого поиска. При этом, если пользователю необходимо выполнить то же исследование, ему / ей нечего делать, кроме как нажать кнопку «Отправить»; в противном случае пользователь может изменить необходимые поля и затем выполнить поиск. Это небольшое улучшение сэкономило много времени пользователям этого проекта и было высоко оценено.

Окончательный результат этой статьи показан ниже и также доступен как JSFiddle :

Разметка

Первым шагом является создание формы для улучшения. Если вы будете использовать этот подход в проекте, над которым вы работаете, у вас будет свой собственный со своими конкретными полями, но для примера здесь я создам фиктивный, содержащий разные типы для каждого поля. Например, я буду использовать searchtextemailcheckboxradiodate Таким образом, вы можете увидеть, как этот метод работает с различными типами.

Больше нечего сказать о форме, поэтому вот код, который мы будем использовать:

 <form name="form" id="form">
   <label for="search">This is the main search field:</label>
   <input type="search" name="search" id="search" />
   <label for="text">This a text field:</label>
   <input type="text" name="text" id="text" />
   <label for="email">This an email field:</label>
   <input type="email" name="email" id="email" />
   <label>This a set of checkbox:</label>
   <label>
      Checkbox1:
      <input type="checkbox" name="checkbox[]" value="checkbox1" />
   </label>
   <label>
      Checkbox2:
      <input type="checkbox" name="checkbox[]" value="checkbox2" />
   </label>
   <label>This a set of radio buttons:</label>
   <label>
      Radio1:
      <input type="radio" name="radio" value="radio1" checked />
   </label>
   <label>
      Radio2:
      <input type="radio" name="radio" value="radio2" />
   </label>
   <label>
      Radio3:
      <input type="radio" name="radio" value="radio3" />
   </label>
   <label for="date">This a date field:</label>
   <input type="date" name="date" id="date" />

   <input type="reset" value="Reset" />
   <input type="submit" value="Submit" />
</form>

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

 <ol id="searches-list">
</ol>

Это оно! Нашей демонстрации не нужны другие элементы, по крайней мере, не статичные, как мы увидим в следующем разделе.

Стиль

По умолчанию в списке старых поисков будет отображаться только значение основного поля, а подсписок имени / значения поля будет скрыт. Это полезно, особенно если у вас есть форма с множеством полей, потому что весь список может легко стать длинным, настолько длинным, что пользователю нужно прокручивать. Как всегда, мы также хотим учитывать, что показ чего-либо только тогда, когда пользователь наводит элемент на элемент, является плохим подходом из-за проблемы доступности. Поэтому мы отобразим подсписок, когда основное значение получит фокус. Это делается с помощью следующего CSS:

 #searches-list > li:hover dl,
#searches-list > li:focus dl
{
   display: block;
}

#searches-list dl
{
   margin: 0;
   display: none;
}

Наконец, мы хотим дать визуальную подсказку, что список может что-то делать, поэтому мы также изменим курсор на указатель:

 #searches-list
{
   cursor: pointer;
}

Теперь, когда мы покончили со стилем, пришло время обсудить бизнес-логику, которая способствует улучшению.

Деловая логика

Эта небольшая демонстрация будет использовать jQuery и jQuery.deserialize , поэтому первое, что вам нужно сделать, это взять их копии и включить их на страницу. Вам также необходимо знать API веб-хранилища , поэтому я рекомендую вам прочитать статью «Обзор API веб-хранилища» .

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

 var $searchesList = $('#searches-list');
var $form = $('#form');

Затем нам нужно проверить, сохранен ли пользователь уже в поиске. Если это так, мы сохраним их в переменную, иначе мы инициализируем переменную в пустой массив:

 var searches = window.localStorage.getItem('searches');
searches = (searches === null) ? [] : JSON.parse(searches);

Очень образно я назвал ключ, в котором код будет хранить поиски, как «поиски». Во втором утверждении мне нужно было использовать метод JSON.parse()

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

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

Когда пользователь заполняет форму и отправляет ее, нам нужно сохранить значения, вставленные в локальное хранилище, до отправки запроса. Для этого мы сначала сериализуем форму с помощью метода serialize() В этой демонстрации мы не будем хранить один и тот же поиск несколько раз, поэтому код ищет дубликаты и удаляет их. Наконец, в демоверсии хранится максимум 10 запросов на пользователя, но вы меняете это значение на любое другое. После того, как мы выполнили все эти операции поиска, нам нужно сохранить их в локальном хранилище.

Это достигается с помощью следующего кода:

 $form.submit(function(event) {
   // Serializes the form
   var currentSearch = $(this).serialize();
   searches.unshift(currentSearch);
   // Removes the duplicates
   for(var i = 1; i < searches.length; i++) {
      if (searches[0] === searches[i]) {
         searches.splice(i, 1);
      }
   }

   // Stores only the last 10 searches
   if (i === searches.length && searches.length > 10) {
      searches.pop();
   }

   // Stores the new list into the local storage
   window.localStorage.setItem('searches', JSON.stringify(searches));
});

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

До сих пор на странице можно было хранить выполненные поиски, но нам нужно показать список пользователю, чтобы, если он щелкнет по одному из элементов, форма автоматически заполнилась. Для этой последней части мы создадим функцию buildSearchesList() Внутри него мы очищаем любой ранее созданный список и затем перебираем старые поиски. Как я уже упоминал, каждый элемент показанного списка будет отображать в виде мнемонического имени значение основного поля, а подсписок, содержащий все поля формы, отображается только тогда, когда пользователь наводит указатель мыши на мнемоническое имя или фокусируется на нем. Каждый раз, когда пользователь нажимает или нажимает клавишу ВВОД или ПРОБЕЛ в элементе списка, форма автоматически заполняется с использованием выбранного набора значений.

На основании этого описания каркас функции выглядит следующим образом:

 function buildSearchesList(searches, $searchesList, $form) {
   $searchesList.empty();

   for (var i = 0; i < searches.length; i++) {
      // Other code goes here...
   }
}

Внутри for Затем мы перебираем свойства этого объекта, чтобы создать подсписок, содержащий имя и значения полей. Подсписок создается с использованием элемента dldtdd

Код, который реализует эти шаги, представлен ниже:

 var params = JSON.parse('{"' +
   decodeURIComponent(
      searches[i]
         .replace(/&/g, '","')
         .replace(/=/g, '":"')
         .replace(/\+/g, ' ')
   ) +
   '"}'
);

var text = '<dl>';
for (var key in params) {
   text += '<dt>' + key + ':</dt><dd> ' + params[key] + '</dd>';
}
text += '</dl>';

Теперь, когда мы создали элемент списка предыдущих поисков, нам нужно добавить его в список, а также указать, что если пользователь щелкнет или нажмет одну из двух клавиш, упомянутых перед автозаполнением формы. Форма автоматически заполняется плагином jQuery.deserialize и вызовом его метода deserialize deserialize() Но поскольку мы находимся в цикле и имеем дело с обработчиками событий, мы должны заключить код во IIFE, чтобы избежать проблем с закрытием. Наконец, каждый элемент списка ( litabindex="0"TAB . Код, который реализует эту последнюю часть, приведен ниже:

 (function(searchData) {
   $searchesList.append(
      $('<li tabindex="0">')
         .text(params['search'])
         .on('click keypress', function(event) {
            if (
               event.type !== 'keypress' ||
               event.keyCode === 13 ||
               event.keyCode === 32
            ) {
               $form
                  .trigger('reset')
                  .deserialize(searchData);
            }
         })
         .append(text)
   );
})(searches[i]);

С этим последним фрагментом мы завершили нашу демонстрацию. Еще раз, окончательный результат этой статьи показан ниже и также доступен как JSFiddle :

Вывод

В этой статье я рассмотрел простую технику для повышения удобства работы ваших пользователей в случае, если у вашего проекта есть форма, которая заполняется много раз в течение обычной сессии. Используя jQuery и jQuery.deserialize, в дополнение к API веб-хранилища мы создали страницу, которая может хранить заданный набор запросов и восстанавливать их при необходимости. Надеюсь, вам понравилась статья, и вы нашли ее полезной.