Skip to content

Latest commit

 

History

History
106 lines (85 loc) · 11.9 KB

File metadata and controls

106 lines (85 loc) · 11.9 KB

FormStorage — сериализация и сохранение форм в localStorage

FormStorage — это небольшая Javascript-библиотека для сериализации и хранения Web-форм в localStorage, распространяемая по лицензии MIT. Её основное предназначение — сохранять вводимые пользователем данные для избежания потерь из-за внезапного закрытия окна, ухода со страницы и т.п. Основная область применения — заполнение больших форм (например, при оформлении каких-либо документов) или написание сообщений и комментариев в онлайн-сообществах.

Библиотека состоит из двух классов: FormSerializer, выполняющий только сериализацию и десереализиацию данных формы в обычный Javascript object, и FormStorage, который отвечает за сохранение и загрузку данных формы в localStorage, а также их автоматическое удаление после успешной отправки формы.

Сериализация с помощью класса FormSerializer

В классе FormSerializer предусмотрено два статических метода:

  • serialize(form_element) — принимает объект типа HTMLFormElement, возвращает object с данными формы вида { 'имя1' : 'значение_поля1', 'имя2' : 'значение_поля2', 'имя3[]': ['массив','значений'], … }
  • unserialize(form_element,data) — принимает форму (объект типа HTMLFormElement) и заполняет её значениями из объекта data.

Пример:

// сериализуем содержимое формы post_form в переменную data
const data = FormSerializer.serialize(document.getElementById('post_form'));
// и восстанавливаем эти данные в форме my_form2
FormSerializer.unserialize(document.getElementById('my_form2'),data);

Особенности сериализации форм

  • У сохраняемых полей обязательно должен быть задан атрибут name.
  • Игнорируются поля, для которых установлено autocomplete="off".
  • Из-за ограничений безопасности не сохраняются значения полей типа password и file.
  • Поддерживаются элементы input (включая checkboxes и radiobuttons), textarea, select с одиночным и множественным выбором.
  • Корректно обрабатываются несколько input-элементов с одинаковым именем (только если в имени содержится []).
  • НЕ сохраняются какие-либо data-атрибуты, а также атрибуты min и max для range-элементов, а также значения кнопок.
  • Если в сериализованных данных не указан ключ для какого-либо поля, это поле останется без изменений.
  • Если в сериализованных данных указан какой-либо ключ, а форме отсутствует поле с таким именем, эта пара ключ-значение будет проигнорирована.

Обработка формы с помощью FormStorage

Для автосохранения формы нужно создать объект типа FormStorage, вызвав его конструктор с параметрами form_element и options. Параметр form_element содержит DOM-элементы формы, которую нужно сохранять, объект optons может содержать следующие поля:

  • storage_key — название ключа в localStorage, в который будет сохраняться содержимое формы. Обязательный параметр.
  • skip_autoloading — если true, пропустить автоматическую начальную загрузку уже сохранённых в localStorage данных. По умолчанию false.
  • headers — объект с дополнительными HTTP-заголовками, которые будут переданы при отправке формы через XMLHttpRequest с помощью FormStorage. По умолчанию отсутствуют.
  • wait_input — если равен true, сохранение формы начнётся только после того, как пользователь сделает ввод хотя бы в одно поле формы. Позволяет избежать замусоривания localStorage данными пустых форм. По умолчанию — false.
  • save_on_exit— если true, обработчик, который сохраняет форму, устанавливается на событие pagehide (вызывается при выходе пользователя со страницы). По умолчанию — true.
  • autosave_time — интервал, через который делается автосохранение, в секундах. Если равно нулю, отрицательно или содержит нечисловое значение, автосохранение будет выключено. Значение по умолчанию — 10 секунд.

Для того, чтобы сохранить или загрузить данные вручную, для созданного объекта FormStorage можно явно вызывать методы load и save без параметров.

Пример простого вызова:

const form_storage = new FormStorage(document.getElementById('post_form'),{ 'storage_key': 'ExampleFormData' });

Более сложный вариант с определением всех настроек:

const form_storage = new FormStorage(document.getElementById('my_form2'),
{ // параметр options
 'storage_key' : 'SecondFormData', // имя ключа в localStorage
 'skip_autoloading' : true, // не загружать форму автоматически, дальше мы сделаем это вручную
 'headers' : { 'X-Sender' : 'FormStorage' } }, // при отправке формы добавим заголовок, по которому сервер сможет распознать, что форма отправлена через XMLHttpRequest
 'wait_input' : true, // сохраняем форму только после того, как пользователь сделал ввод
 'save_on_exit' : true,
 'autosave_time' : 5, // сохраняем форму каждые 5 секунд, а не 10
}
);
// тут может быть проверка каких-либо условий, нужно ли загружать сохранённую форму
form_storage.load(); // явная загрузка формы

Отправка формы на сервер, хуки и работа с WYSIWYG-редакторами

FormStorage автоматически добавляет обработчик события onsubmit, который отменяет стандартную обработку формы, отправляет её содержимое на сервер через AJAX-запрос и добавляет к этому запросу заголовки из options.headers. Если сервер возвращает статусы 200, 204 или 206, происходит автоматический переход на итоговый URL. При статусе 201 — переход по адресу из заголовка Location. Если адрес отличается от адреса страницы с формой только хеш-частью, будет сделано принудительное обновление страницы. В остальных случаях вызывается обработчик ошибок onSubmitError. Если нужно изменить эту логику, замените метод onSubmitResult на свой (в качестве параметра он принимает объект XMLHttpResult).

Совет: Добавьте специальный заголовок в запросы FormStorage, чтобы сервер мог их отличать от обычных отправок формы. Для таких запросов лучше возвращать статус 201 с заголовком Location, чтобы избежать повторной загрузки страницы.

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

  • onBeforeSave — перед началом сериализации формы. Вызывается без параметров.
  • onSave — после выполнения сериализации формы, но перед её сохранением в localStorage. В качестве параметра принимает объект с сохраняемыми полями в формате { "поле1":"значение", "поле2[]": ["массив","значений"] }, содержимое которого можно при необходимости изменять.
  • onLoad — после парсинга данных из localStorage перед выгрузкой их в форму. Принимает объект в таком же формате, как и onSave.
  • onSubmitError — при возникновении ошибки отправки формы на сервер (код ответа сервера не равен 200, 201, 204 или 206).
  • onDecodeError — при ошибки парсинга JSON, загруженного из localStorage.

По умолчанию все хуки пусты (ничего не делают), кроме onSubmitError, в котором текст ошибки выводится в консоль.

Многие WYSIWYG-редакторы перед отправкой формы требуют явно вызвать метод, который сохранит содержимое редактора в поле формы, или поместить в редактор текст при загрузки страницы. Это удобно делать в хуках onBeforeSave и onLoad соответственно. Пример таких обработчиков для редактора Quill:

const quill = new Quill('.quill_full_editor', {
modules: {
  toolbar: "#quill-toolbar",    
},   
  theme: 'snow',
  placeholder: 'Здесь будет новая заметка…',
});

const postform = documemt.getElementById('postform');
// We will skip autoloading because of we need to add onLoad hook. So we call fstor.load() later explicitly.
const fstor = new FormStorage(postform,'FormStorage_draft',headers : { 'Accept' : 'application/json' }, skip_autoloading : true});

fstor.onLoad = function(data) { // переопределяем хук onLoad
  if ('post[text]' in data) quill.root.innerHTML=data['post[text]'];
}

fstor.onBeforeSave = function(data) { // переопределяем хук onBeforeSave
  data['post[text]']=quill.getSemanticHTML();
}

fstor.load();