Розробка форми з автозбереженням прогресу на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка форми з автозбереженням прогресу на сайті
Середня
від 1 робочого дня до 3 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка форми з автозбереженням прогресу на сайті

Довгі форми — анкети, заявки, опитування — втрачають користувачів, якщо ті випадково закрили вкладку або з'єднання перервалося. Автозбереження вирішує цю проблему: дані переживають перезавантаження сторінки та повертаються при наступному візиті.

Стратегії зберігання

LocalStorage — швидко, без сервера, але привязано до пристрою та браузера. Підходить для анонімних форм або чорновиків.

IndexedDB — те ж саме, але для великих даних (файли, бінарники). Використовуємо через idb або localforage.

Сервер (API) — дані доступні з будь-якого пристрою. Потребує авторизації або часового токена сесії.

Гібрид — спочатку в localStorage (миттєво), потім синхронізація з сервером у фоні.

Реалізація через localStorage

class FormAutoSave {
  constructor(formId, key, debounceMs = 800) {
    this.form = document.getElementById(formId);
    this.key = key;
    this.debounceMs = debounceMs;
    this._timer = null;
    this._init();
  }

  _init() {
    this._restore();
    this.form.addEventListener('input', () => this._schedulesSave());
    this.form.addEventListener('change', () => this._schedulesSave());
    this.form.addEventListener('submit', () => this.clear());
  }

  _schedulesSave() {
    clearTimeout(this._timer);
    this._timer = setTimeout(() => this._save(), this.debounceMs);
  }

  _save() {
    const data = {};
    const elements = this.form.elements;

    for (const el of elements) {
      if (!el.name) continue;
      if (el.type === 'checkbox') {
        data[el.name] = el.checked;
      } else if (el.type === 'radio') {
        if (el.checked) data[el.name] = el.value;
      } else {
        data[el.name] = el.value;
      }
    }

    localStorage.setItem(this.key, JSON.stringify({
      data,
      savedAt: Date.now(),
    }));

    this._updateIndicator('saved');
  }

  _restore() {
    const raw = localStorage.getItem(this.key);
    if (!raw) return;

    const { data, savedAt } = JSON.parse(raw);
    const age = Date.now() - savedAt;
    if (age > 7 * 24 * 60 * 60 * 1000) { // 7 днів — застаріло
      this.clear();
      return;
    }

    for (const [name, value] of Object.entries(data)) {
      const el = this.form.elements[name];
      if (!el) continue;
      if (el.type === 'checkbox') el.checked = value;
      else if (el.type === 'radio') {
        const radio = this.form.querySelector(`[name="${name}"][value="${value}"]`);
        if (radio) radio.checked = true;
      } else {
        el.value = value;
      }
    }

    this._updateIndicator('restored');
  }

  clear() {
    localStorage.removeItem(this.key);
  }

  _updateIndicator(state) {
    const el = document.querySelector('[data-autosave-status]');
    if (!el) return;
    el.textContent = state === 'saved' ? 'Збережено' : 'Чорновик відновлено';
    el.dataset.state = state;
  }
}

// Використання
new FormAutoSave('application-form', 'form_draft_application_v1');

Синхронізація з сервером

Коли користувач авторизований, чорновик зберігається на сервері:

async function syncDraftToServer(formKey, data) {
  try {
    await fetch('/api/drafts', {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-TOKEN': window.csrfToken,
      },
      body: JSON.stringify({ key: formKey, data }),
    });
  } catch {
    // Fallback — залишаємо в localStorage, спробуємо пізніше
  }
}

На Laravel:

// routes/api.php
Route::middleware('auth')->group(function () {
    Route::put('/drafts', [DraftController::class, 'store']);
    Route::get('/drafts/{key}', [DraftController::class, 'show']);
    Route::delete('/drafts/{key}', [DraftController::class, 'destroy']);
});

// DraftController
public function store(Request $request)
{
    Draft::updateOrCreate(
        ['user_id' => auth()->id(), 'key' => $request->key],
        ['data' => $request->data, 'expires_at' => now()->addDays(30)]
    );
    return response()->noContent();
}

Індикатор стану

Користувач повинен бачити, коли форма збережена. Три стани: "Зберігається...", "Збережено 5 хвилин тому", "Помилка збереження".

// React-варіант
function AutoSaveIndicator({ status, savedAt }) {
  const labels = {
    saving: 'Зберігається...',
    saved: savedAt ? `Збережено ${formatRelative(savedAt)}` : 'Збережено',
    error: 'Помилка збереження',
    idle: '',
  };

  return (
    <span className={`autosave-badge autosave-badge--${status}`}>
      {labels[status]}
    </span>
  );
}

Мультишагові форми (wizard)

Для wizard-форм зберігаємо не тільки дані полів, але й поточний крок:

const state = {
  step: currentStep,
  fields: collectFields(),
  completedSteps: [1, 2, 3],
};
localStorage.setItem('wizard_draft', JSON.stringify(state));

При відновленні питаємо користувача: "Продовжити з кроку 3 або почати заново?" — модальне вікно з двома кнопками.

Конфлікти при паралельному редагуванні

Якщо форма відкрита в кількох вкладках, використовуємо localStorage event для синхронізації:

window.addEventListener('storage', (e) => {
  if (e.key === 'form_draft_application_v1') {
    const remote = JSON.parse(e.newValue);
    if (remote.savedAt > localSavedAt) {
      applyRemoteData(remote.data);
    }
  }
});

Терміни

Автозбереження в localStorage з відновленням та індикатором — 2–3 робочих дні. З серверною синхронізацією, підтримкою wizard, конфлікт-резолюцією та історією чорновиків — 5–7 днів.