FormStorage — это небольшая Javascript-библиотека для сериализации и хранения Web-форм в localStorage, распространяемая по лицензии MIT. Её основное предназначение — сохранять вводимые пользователем данные для избежания потерь из-за внезапного закрытия окна, ухода со страницы и т.п. Основная область применения — заполнение больших форм (например, при оформлении каких-либо документов) или написание сообщений и комментариев в онлайн-сообществах.
Библиотека состоит из двух классов: FormSerializer, выполняющий только сериализацию и десереализиацию данных формы в обычный Javascript object, и FormStorage, который отвечает за сохранение и загрузку данных формы в localStorage, а также их автоматическое удаление после успешной отправки формы.
В классе 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, вызвав его конструктор с параметрами 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(); // явная загрузка формы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();