Stimulus предоставляет удобный механизм для связи контроллера с элементами DOM через outlets. Outlets позволяют легко получать доступ к вложенным элементам, избегая громоздкого поиска по селекторам в коде и упрощая поддержку приложения.
Outlet — это ссылка на элемент DOM, который контроллер может использовать как свойство. Для создания outlet в HTML используется атрибут:
<div data-controller="example" data-example-target="container">
<button data-example-target="button">Нажми меня</button>
</div>
В этом примере:
data-controller="example" связывает элемент с
контроллером ExampleController.data-example-target="button" объявляет элемент как
target, который можно использовать как outlet в контроллере.В Stimulus outlet не обязательно совпадает с target
по имени, но target — это чаще всего элемент, на который контроллер
будет ссылаться. Для работы с outlet нужно определить его в контроллере
через метод static outlets = [...].
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static outlets = ["button"];
connect() {
console.log(this.buttonOutlet); // доступ к элементу через outlet
}
}
Здесь this.buttonOutlet автоматически ссылается на
DOM-элемент с соответствующим data-атрибутом.
Stimulus позволяет объявлять множественные элементы как один
outlet, что полезно для работы с коллекциями элементов. Для
этого в static outlets указывается имя и добавляется
[]:
static outlets = ["item[]"];
В HTML:
<div data-controller="list">
<div data-list-outlet="item"></div>
<div data-list-outlet="item"></div>
</div>
После подключения контроллера можно работать с массивом элементов:
this.itemOutlets.forEach(el => el.classList.add("highlight"));
Outlets поддерживают проверку наличия элемента через
hasOutlet и hasOutlets:
if (this.hasButtonOutlet) {
this.buttonOutlet.disabled = true;
}
if (this.hasItemOutlets) {
console.log(`Найдено ${this.itemOutlets.length} элементов`);
}
Это позволяет безопасно обращаться к элементам, даже если они не присутствуют в DOM.
Outlets могут ссылаться на другие контроллеры, что облегчает взаимодействие между компонентами:
<div data-controller="parent">
<div data-parent-outlet="child" data-controller="child"></div>
</div>
В родительском контроллере:
static outlets = ["child"];
connect() {
this.childOutlet.someChildMethod();
}
Здесь childOutlet не просто DOM-элемент, а объект
контроллера ChildController, благодаря чему можно вызывать
методы дочернего контроллера напрямую.
Stimulus автоматически отслеживает изменения DOM и обновляет outlets.
Если элемент был добавлен динамически после подключения контроллера,
outlet станет доступен без дополнительного кода. Аналогично, при
удалении элемента outlet перестает существовать, а
hasOutlet вернет false.
const newButton = document.createElement("button");
newButton.dataset.exampleOutlet = "button";
this.element.appendChild(newButton);
console.log(this.hasButtonOutlet); // true после добавления
hasOutlet
перед манипуляцией, чтобы избежать ошибок в динамическом DOM.submitButtonOutlet,
cancelButtonOutlet).itemOutlets) для сортировки
или подсветки.Outlets делают структуру кода чистой и
декларативной, сокращая количество поиска элементов через
querySelector и повышая читаемость контроллера.