Stimulus — это легковесный JavaScript-фреймворк, ориентированный на улучшение HTML через привязку поведения к элементам страницы с помощью контроллеров. Валидация на клиентской стороне является одной из ключевых задач при работе с формами и интерактивными интерфейсами. Stimulus предоставляет удобный способ структурировать эту логику, сохраняя код чистым и легко поддерживаемым.
Валидация реализуется через контроллеры, которые связываются с
формами и их полями с помощью data-атрибутов. Основная
идея заключается в том, что каждый элемент формы может быть “снабжен”
контроллером, который обрабатывает события input,
change или submit.
Контроллер создаётся командой:
rails generate stimulus form_validation
или вручную создается файл
form_validation_controller.js:
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["email", "password", "submit"]
connect() {
this.submitTarget.disabled = true
}
validate() {
const emailValid = this.validateEmail(this.emailTarget.value)
const passwordValid = this.passwordTarget.value.length >= 8
if (emailValid && passwordValid) {
this.submitTarget.disabled = false
} else {
this.submitTarget.disabled = true
}
}
validateEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return re.test(email)
}
}
В данном примере:
HTML-разметка формы связывается с контроллером через атрибуты
data-controller и data-target:
<form data-controller="form-validation" data-action="input->form-validation#validate">
<label>Email</label>
<input type="email" data-form-validation-target="email">
<label>Пароль</label>
<input type="password" data-form-validation-target="password">
<button type="submit" data-form-validation-target="submit">Отправить</button>
</form>
input вызывается метод validate.Для улучшения UX часто необходимо показывать сообщения об ошибках рядом с полями. В Stimulus это делается через отдельные targets для сообщений об ошибках:
static targets = ["email", "password", "submit", "emailError", "passwordError"]
validate() {
let valid = true
if (!this.validateEmail(this.emailTarget.value)) {
this.emailErrorTarget.textContent = "Некорректный email"
valid = false
} else {
this.emailErrorTarget.textContent = ""
}
if (this.passwordTarget.value.length < 8) {
this.passwordErrorTarget.textContent = "Пароль должен быть не менее 8 символов"
valid = false
} else {
this.passwordErrorTarget.textContent = ""
}
this.submitTarget.disabled = !valid
}
HTML для сообщений:
<div>
<input type="email" data-form-validation-target="email">
<span data-form-validation-target="emailError" class="error"></span>
</div>
<div>
<input type="password" data-form-validation-target="password">
<span data-form-validation-target="passwordError" class="error"></span>
</div>
Такой подход позволяет поддерживать чистую логику валидации, не смешивая её с HTML-разметкой напрямую.
Stimulus контроллеры легко комбинируются и расширяются. Например, можно вынести повторяющиеся проверки в отдельный validation.js:
export function isEmail(value) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
return re.test(value)
}
export function minLength(value, length) {
return value.length >= length
}
И использовать их в контроллере:
import { Controller } from "@hotwired/stimulus"
import { isEmail, minLength } from "../utils/validation"
export default class extends Controller {
static targets = ["email", "password", "submit", "emailError", "passwordError"]
validate() {
let valid = true
if (!isEmail(this.emailTarget.value)) {
this.emailErrorTarget.textContent = "Некорректный email"
valid = false
} else {
this.emailErrorTarget.textContent = ""
}
if (!minLength(this.passwordTarget.value, 8)) {
this.passwordErrorTarget.textContent = "Пароль должен быть не менее 8 символов"
valid = false
} else {
this.passwordErrorTarget.textContent = ""
}
this.submitTarget.disabled = !valid
}
}
Это позволяет легко добавлять новые правила валидации и переиспользовать их в разных контроллерах.
Помимо проверки во время ввода, можно подключать проверку при отправке формы:
submitForm(event) {
if (!this.validate()) {
event.preventDefault()
}
}
HTML:
<form data-controller="form-validation" data-action="submit->form-validation#submitForm">
Такой подход предотвращает отправку формы, если хотя бы одно поле не прошло проверку, гарантируя безопасность на клиенте до взаимодействия с сервером.
Stimulus хорошо работает с формами, где зависимости между полями важны. Например, подтверждение пароля:
static targets = ["password", "passwordConfirm", "passwordError", "passwordConfirmError"]
validate() {
let valid = true
if (this.passwordTarget.value !== this.passwordConfirmTarget.value) {
this.passwordConfirmErrorTarget.textContent = "Пароли не совпадают"
valid = false
} else {
this.passwordConfirmErrorTarget.textContent = ""
}
this.submitTarget.disabled = !valid
}
Подобная структура позволяет легко добавлять новые проверки без переписывания основной логики.
Stimulus обеспечивает структурированный, модульный и реактивный подход к клиентской валидации, позволяя писать чистый и поддерживаемый код без громоздких библиотек. Ключевыми преимуществами являются targets для отслеживания элементов, actions для событий и modularity для переиспользования правил.