Stimulus обеспечивает удобный способ управления поведением интерфейса, но для полноценной работы с формами часто требуется интеграция с серверной валидацией. Это позволяет сразу отображать ошибки, полученные от сервера, без полной перезагрузки страницы, сохраняя отзывчивость приложения.
Для работы с серверной валидацией создается Stimulus-контроллер, привязанный к форме. Классический подход включает следующие элементы:
submit,
input или change.Пример структуры контроллера:
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["form", "submit", "field", "errors"];
static values = { url: String, method: String };
submit(event) {
event.preventDefault();
this.clearErrors();
this.sendData();
}
sendData() {
const formData = new FormData(this.formTarget);
fetch(this.urlValue, {
method: this.methodValue || "POST",
body: formData,
headers: {
"Accept": "application/json"
}
})
.then(response => response.json())
.then(data => this.handleResponse(data))
.catch(error => console.error("Network error:", error));
}
handleResponse(data) {
if (data.errors) {
this.showErrors(data.errors);
} else {
this.formTarget.reset();
}
}
showErrors(errors) {
for (const [fieldName, messages] of Object.entries(errors)) {
const field = this.fieldTargets.find(f => f.name === fieldName);
if (field) {
const errorContainer = document.createElement("div");
errorContainer.classList.add("field-error");
errorContainer.textContent = messages.join(", ");
field.after(errorContainer);
}
}
}
clearErrors() {
this.errorsTargets.forEach(el => el.remove());
}
}
Форма должна содержать data-controller,
data-target и при необходимости
data-action:
<form data-controller="validation"
data-validation-url-value="/users"
data-validation-method-value="POST"
data-action="submit->validation#submit">
<input type="text" name="username" data-validation-target="field">
<input type="email" name="email" data-validation-target="field">
<button type="submit" data-validation-target="submit">Отправить</button>
</form>
Контейнеры для ошибок создаются динамически контроллером после
получения ответа сервера. Для удобства можно добавить глобальный
контейнер data-validation-target="errors", куда будут
выводиться все сообщения.
Использование fetch с Promise
позволяет:
Пример управления состоянием кнопки:
submit(event) {
event.preventDefault();
this.submitTarget.disabled = true;
this.clearErrors();
this.sendData();
}
handleResponse(data) {
this.submitTarget.disabled = false;
if (data.errors) {
this.showErrors(data.errors);
} else {
this.formTarget.reset();
}
}
Серверная валидация может возвращать ошибки в разных форматах. Stimulus-контроллер должен быть готов к:
{ errors: { field: ["message"] } }.500 Internal Server Error),
которые можно отобразить в глобальном контейнере.catch с выводом
уведомления о недоступности сервера.Для улучшения UX рекомендуется комбинировать серверную и клиентскую валидацию:
Такой подход снижает количество лишних запросов к серверу и делает интерфейс более отзывчивым.
targets.FormData и fetch
обеспечивает удобный асинхронный обмен данными.