Обработка отправки форм

Stimulus — легковесный JavaScript-фреймворк, который позволяет добавлять поведение на HTML-страницы, используя декларативный подход. Одной из наиболее частых задач является управление формами: отслеживание отправки, валидация, асинхронная обработка и динамическое обновление интерфейса. Stimulus предоставляет для этого удобные механизмы через контроллеры, экшены и значения (values).


Подключение контроллера к форме

Для начала контроллер подключается к форме через атрибут data-controller:

<form data-controller="form" data-action="submit->form#submit">
  <input type="text" name="username" />
  <button type="submit">Отправить</button>
</form>
  • data-controller="form" — подключает контроллер form_controller.js.
  • data-action="submit->form#submit" — связывает событие submit с методом submit контроллера.

В Stimulus каждое событие связывается с конкретным методом, что делает код структурированным и легко поддерживаемым.


Определение контроллера

Контроллер описывается как класс, наследуемый от Controller:

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  submit(event) {
    event.preventDefault();
    const formData = new FormData(this.element);

    // Пример обработки данных
    const data = Object.fromEntries(formData.entries());
    console.log("Отправка данных:", data);

    this.sendRequest(data);
  }

  async sendRequest(data) {
    try {
      const response = await fetch(this.element.action, {
        method: this.element.method,
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
      });

      if (!response.ok) throw new Error("Ошибка при отправке формы");

      const result = await response.json();
      this.handleSuccess(result);
    } catch (error) {
      this.handleError(error);
    }
  }

  handleSuccess(result) {
    console.log("Форма успешно отправлена:", result);
  }

  handleError(error) {
    console.error("Ошибка формы:", error);
  }
}
  • event.preventDefault() блокирует стандартное поведение браузера.
  • FormData позволяет собрать данные формы в удобном виде.
  • fetch используется для асинхронной отправки на сервер.

Использование значений для динамических параметров

Stimulus позволяет задавать values, чтобы хранить настраиваемые параметры контроллера:

<form data-controller="form"
      data-form-url-value="/api/submit"
      data-action="submit->form#submit">
  <input type="text" name="username" />
  <button type="submit">Отправить</button>
</form>
export default class extends Controller {
  static values = { url: String }

  submit(event) {
    event.preventDefault();
    const formData = Object.fromEntries(new FormData(this.element).entries());
    this.sendRequest(formData, this.urlValue);
  }

  async sendRequest(data, url) {
    const response = await fetch(url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(data)
    });

    const result = await response.json();
    console.log(result);
  }
}
  • Значения позволяют легко менять параметры контроллера без изменения JavaScript-кода.
  • Объект this.urlValue автоматически связывается с атрибутом data-form-url-value.

Управление состоянием формы

Stimulus упрощает динамическое изменение состояния формы, например, при отправке:

submit(event) {
  event.preventDefault();
  this.element.querySelector("button").disabled = true;
  
  const data = Object.fromEntries(new FormData(this.element).entries());
  this.sendRequest(data);
}

handleSuccess(result) {
  this.element.reset();
  this.element.querySelector("button").disabled = false;
  alert("Форма успешно отправлена");
}

handleError(error) {
  this.element.querySelector("button").disabled = false;
  console.error(error);
}
  • Кнопка отправки блокируется до завершения запроса.
  • После успешной отправки форма очищается, а кнопка становится активной.
  • Обработка ошибок также возвращает форму в исходное состояние.

Делегирование событий и множественные формы

Если на странице несколько форм, можно использовать декларативные экшены с идентификаторами:

<form data-controller="form" data-action="submit->form#submit" data-form-id-value="1">
  ...
</form>
<form data-controller="form" data-action="submit->form#submit" data-form-id-value="2">
  ...
</form>

Контроллер получает уникальные значения через data-form-id-value:

static values = { id: Number }

submit(event) {
  event.preventDefault();
  console.log("ID формы:", this.idValue);
}
  • Каждая форма работает автономно, не вмешиваясь в другие формы.
  • Значения позволяют динамически различать формы и их обработку.

Асинхронная валидация

Stimulus позволяет проверять данные перед отправкой:

submit(event) {
  event.preventDefault();
  const username = this.element.querySelector("input[name='username']").value;

  if (!username || username.length < 3) {
    this.showError("Имя пользователя должно быть минимум 3 символа");
    return;
  }

  const data = Object.fromEntries(new FormData(this.element).entries());
  this.sendRequest(data);
}

showError(message) {
  const errorElement = this.element.querySelector(".error") || document.createElement("div");
  errorElement.className = "error";
  errorElement.textContent = message;
  this.element.appendChild(errorElement);
}
  • Валидация происходит до отправки запроса.
  • Сообщения об ошибках добавляются динамически в DOM.
  • Можно расширять для проверки на сервере и обработку асинхронных ошибок.

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