Stimulus を学ぶ
Stimulus Handbook を読んだので、かいつまみました。
コードは Handbook のものを載せています(一部改変しています)。
コントローラを用意する
どのコントローラも以下のように定義する。
ファイル名は規約に従ったものにしておく(xxxx_controller.js)。
// app/javascript/controllers/hello_controller.js import { Controller } from "stimulus" export default class extends Controller { // この中にいろいろ書いていく }
コントローラをHTMLに接続する
以下のように、HTML側で接続を宣言する。
以下の場合は、div 要素と hello コントローラ(のインスタンス)が接続される。
%div{ data: { controller: 'hello' }} -# ...
コントローラが接続されるときに connect() が走る
上記のHTML要素が読み込まれるとき、つまりコントローラが接続されるとき、connect() の中に書いた処理が走る。
import { Controller } from "stimulus" export default class extends Controller { connect() { console.log("Hello, Stimulus!") } }
Action Descriptor(アクション記述子)でイベントをトリガーにする
以下のように書くことで、イベントをトリガーにコントローラのメソッドを呼び出せる。
action: 'click->hello#greet'
のところがポイント。
action: 'イベント名->コントローラ名#メソッド名'
という関係になるように書けばOK。
import { Controller } from "stimulus" export default class extends Controller { // 先ほどの connect() をリネームしただけ greet() { console.log("Hello, Stimulus!") } }
%div{ data: { controller: 'hello' }} %button{ data: { action: 'click->hello#greet' }} Greet
Targets でコントローラからHTML要素を参照する
Targets を宣言し、それに紐づけた要素はコントローラ内で参照できるようになる。
↓の例だと、input 要素を name という名前で参照できるようにしている。
import { Controller } from "stimulus" export default class extends Controller { // Targets の宣言 static targets = ["name"] greet() { // 参照するときは this.xxxxTarget と書く const element = this.nameTarget const name = element.value console.log(`Hello, ${name}!`) } }
%div{ data: { controller: 'hello' }} -# nameTarget とHTML要素を紐づける %input{ type: :text, data: { 'hello-target': 'name' } } %button{ data: { action: 'click->hello#greet' }} Greet
Targets で提供されるプロパティ
Targets を宣言すると、先述の this.xxxxTarget のほかに this.xxxxTarget と this.hasXxxxTarget も提供される。
- this.xxxxTarget:xxxxTarget と最初に紐づけた要素を取得する
- this.xxxxTargets:xxxxTarget と紐づけた要素を配列で取得する(1つの Target を複数の要素に紐づけることができる)
- this.hasXxxxTarget:接続している要素の中に xxxxTarget と紐づけた要素があるかどうか(boolean)
Action Descriptor のイベント部分はショートハンドがある
Action Descriptor のイベント部分は、要素の種類によってデフォルト値が決まっている。
そのため、デフォルト値のイベントをそのまま使う場合は記述を省略できる。
先述した以下の例だと、button 要素のデフォルトイベントは click なので、click->hello#greet の click-> の部分は無くてOK。
%div{ data: { controller: 'hello' }} -# %button{ data: { action: 'click->hello#greet' }} Greet -# これでOK %button{ data: { action: 'hello#greet' }} Greet
要素の種類とデフォルトイベントの関係は以下URLを参照されたい。
https://stimulus.hotwire.dev/reference/actions#event-shorthand
Values でHTMLからコントローラに値を渡す
Values を宣言すると、HTMLからコントローラに値を渡すことができる。
URLを渡してコントローラ側で fetch したり、state の初期値をコントローラに渡したりできる。
RailsからHamlにレンダリングした値を、HamlからStimulusコントローラに渡すような使い方もありそう。
以下のように、データ型の概念がある。
%div{ data: { controller: 'slideshow', 'slideshow-index-value': 1 }} -# ...
// app/javascript/controllers/slideshow_controller.js import { Controller } from "stimulus" export default class extends Controller { static targets = ["slide"] // ↓Values の宣言 static values = { index: Number } next() { this.indexValue++ } previous() { this.indexValue-- } // xxxxValueChanged() メソッドを宣言しておけば、Value の値が変わったときに勝手に呼び出される indexValueChanged() { this.showCurrentSlide() } showCurrentSlide() { this.slideTargets.forEach((element, index) => { // this.xxxxValue と書いて参照できる element.hidden = index != this.indexValue }) } }