🔗 コントローラとDOMのマッパー
こんなときに使いたい
- あるコントローラの内部ステートに外部からアクセスしようとする場合
- コントローラから別のコントローラのメソッドを呼び出す必要がある場合
たとえば、コントローラが処理を行うために、今どのページにいるのかという情報を別のコントローラから得る必要があるとします。
<!-- index.html -->
<div data-controller="pagination test" data-pagination-page="1">
<button data-action="test#calculateRouteFromPage">Calculate Route From Page</button>
</div>
Warning
// pagination_controller.js
export default class extends Controller {
get page() {
return this.data.get("page");
}
}
// test_controller.js
export default class extends Controller {
connect() {
this.paginationController = this.application.getControllerForElementAndIdentifier(
this.element,
"pagination"
);
}
calculateRouteFromPage() {
const page = this.paginationController.page;
// レコードなどを取り出す
}
}
Good
// pagination_controller.js
export default class extends Controller {
connect() {
this.element[this.identifier] = this;
}
get page() {
return this.data.get("page");
}
}
// test_controller.js
export default class extends Controller {
calculateRouteFromPage() {
const page = this.element.pagination.page;
// レコードなどを取り出す
}
}
そうする理由
getControllerForElementAndIdentifier
のようなドキュメント化されていないAPIに依存すると、(近い)将来動かなくなる危険を常に伴います。this.element[this.identifier] = this
でシンプルに要素にアクセスすることでコントローラを要素にアタッチすれば、特定のコントローラのインスタンスを明示的に参照できるようになるので、この依存関係を取り除けます。StimulusはMutationObserver
APIを使っているので、コントローラが動的に追加されれば、自分自身のJavaScriptコードやサードパーティのライブラリによってconnect
がこの参照をフックすることを確信できるようになります。
注意
コントローラの識別子にJavaScriptとして無効な文字(-
など)が含まれている場合は、以下のブログ記事で述べているように、camelCaseを使うなどしてJavaScriptに準拠した識別子が生成されるようにする必要があります。また、value
などの既存のプロパティを上書きしないよう注意する必要もあります。
もうひとつの注意点は、StimulusのコントローラはDOMにアタッチされるので、document
のスコープで動作する別のJavaScriptコードがコントローラをつかんで、そのコントローラで定義されているメソッドを実行する可能性があることです。そのため、この方法でどのコントローラを公開するかについては常識的に判断してください。ユースケースによっては、破壊的なアクションを実行するコントローラはスキップする方がよいかもしれません。
概要
原著者の許諾を得て翻訳・公開いたします。