Динамическое изменение полей форм

Stimulus — это легковесный JavaScript-фреймворк, ориентированный на добавление интерактивности к HTML без перегрузки сложной логикой. Его основной принцип — связывание контроллеров с элементами DOM через атрибуты data-*, что позволяет организовать динамическое поведение на страницах с минимальными усилиями. В контексте форм это особенно полезно для управления полями, их валидацией и динамическим отображением.

Создание контроллера для формы

Контроллер Stimulus определяется классом JavaScript, наследующимся от Controller. Основные элементы:

  • targets — элементы, с которыми контроллер будет взаимодействовать.
  • actions — события, на которые контроллер реагирует.
  • values — хранимые данные состояния, доступные для реактивного управления.

Пример базового контроллера для формы:

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

export default class extends Controller {
  static targets = ["input", "output"];

  connect() {
    console.log("Form controller connected");
  }

  updateOutput() {
    this.outputTarget.textContent = this.inputTarget.value;
  }
}

HTML-разметка для этого контроллера:

<div data-controller="form">
  <input type="text" data-form-target="input" data-action="input->form#updateOutput">
  <div data-form-target="output"></div>
</div>

Ключевое здесь — связывание события input с методом контроллера через data-action. Любое изменение в поле автоматически обновляет связанный элемент.

Динамическое добавление и удаление полей

Частая задача — динамическая генерация новых полей в форме. Для этого удобно использовать методы контроллера:

static targets = ["fieldsContainer"];

addField(event) {
  event.preventDefault();
  const newField = document.createElement("input");
  newField.type = "text";
  newField.name = "dynamic_field[]";
  newField.classList.add("dynamic-input");
  this.fieldsContainerTarget.appendChild(newField);
}

removeField(event) {
  event.preventDefault();
  const field = event.target.closest("input");
  if (field) field.remove();
}

HTML для управления динамическими полями:

<div data-controller="form">
  <div data-form-target="fieldsContainer"></div>
  <button data-action="click->form#addField">Добавить поле</button>
</div>

Такое решение обеспечивает чистую и реактивную логику без необходимости обращаться к глобальным селекторам или создавать сложные шаблоны вручную.

Управление видимостью полей

Stimulus позволяет легко показывать и скрывать поля на основе состояния других элементов. Пример:

static targets = ["toggleInput", "dependentField"];

toggleField() {
  this.dependentFieldTarget.hidden = !this.toggleInputTarget.checked;
}

HTML:

<input type="checkbox" data-form-target="toggleInput" data-action="change->form#toggleField">
<input type="text" data-form-target="dependentField" hidden>

Использование hidden вместо display: none в стиле CSS позволяет сохранять семантику формы и упрощает работу с валидацией.

Валидация полей и управление состоянием

Stimulus удобно использовать для локальной валидации перед отправкой формы. Пример проверки на пустое поле:

static targets = ["input"];

validate() {
  this.inputTargets.forEach((input) => {
    if (!input.value.trim()) {
      input.classList.add("error");
    } else {
      input.classList.remove("error");
    }
  });
}

HTML:

<form data-controller="form" data-action="submit->form#validate">
  <input type="text" data-form-target="input">
  <input type="text" data-form-target="input">
  <button type="submit">Отправить</button>
</form>

Такой подход делает форму интерактивной и предотвращает отправку некорректных данных без использования сложных библиотек.

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

Stimulus values позволяют хранить состояние контроллера и автоматически обновлять интерфейс при изменении. Пример управления числом динамических полей:

static values = { count: Number };

addField() {
  this.countValue++;
  const newField = document.createElement("input");
  newField.type = "text";
  newField.name = `dynamic_field_${this.countValue}`;
  this.fieldsContainerTarget.appendChild(newField);
}

HTML:

<div data-controller="form" data-form-count-value="0">
  <div data-form-target="fieldsContainer"></div>
  <button data-action="click->form#addField">Добавить поле</button>
</div>

Это обеспечивает синхронность состояния и DOM, облегчая управление сложными формами.

Итоговая структура

Комбинация targets, actions и values позволяет реализовать:

  • Динамическое добавление и удаление полей.
  • Реактивное отображение полей на основе состояния других элементов.
  • Локальную валидацию без сторонних библиотек.
  • Контролируемое управление состоянием через значения контроллера.

Stimulus сохраняет чистоту HTML и минимализм JavaScript, делая форму легко расширяемой и поддерживаемой. Такой подход подходит для любых интерактивных интерфейсов с большим количеством зависимых полей и условной логики.