※ こちらの記事は、Stimulusの公式ハンドブックを参考に翻訳しつつ、執筆しています。

対象読者
JavasScriptをすこしわかる人
入門編0を読んだ人

前回、stimulus-starterをgitからチェックアウトして、Stimulusフレームワークがどういったものかざっくり動かすところまでご紹介しました。

今回はもう少し、ロジックを掴めるようにしましょう。

具体的には、テキストフィールドに名前を入力してボタンを押したら「こんにちは○○さん」と表示されるようにプログラムを作ります。

フォーム部品を記述

./public/index.htmlを下記のようにしましょう。

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="main.css">
  <script src="bundle.js" async></script>
</head>
<body>
  <div>
    <input type="text">
    <button>こんにちは</button>
  </div>
</body>
</html>

そして、ブラウザを立ち上げてhttp://localhost:9000/にアクセスします。
It works!のままの人はブラウザをリロードしてください。

上記のような単純にテキストフィールドと「こんにちは」ボタンが表示されたかと思います。
ここに、Stimulusを適用させます。

コントローラの作成

Stimulusの根幹の概念として、
StimulusはJavascriptオブジェクト(クラスなど)をDOMと自動的に接続してくれます。
Stimulusでは、接続するJavaScriptオブジェクトのことを「コントローラ」と呼びます。

ではさっそくコントローラを作成してみましょう。
./src/controllers/hello_controller.jsというファイルを作成してください。

hello_controller.jsを下記のようにします。

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
}

次に、HTMLにどのコントローラを接続するのか設定しなければなりません。
HTMLファイルのdivタグにdata-controller=”hello”を追記しましょう。
下記のようにします。

<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <link rel="stylesheet" href="main.css">
  <script src="bundle.js" async></script>
</head>
<body>
  <div data-controller="hello">
    <input type="text">
    <button>こんにちは</button>
  </div>
</body>
</html>

こうすることでDIVタグがDOMとして生成されたときにhelloコントローラのインスタンスを生成し、自動的に接続します。もちろんdivタグではなく別のタグでも同様に設定できます。

できたら、リロードしてみましょう。
一応、コントローラを接続できいるはずなのですが、なにも反応がなくわかりづらいですね。

動作していることを確かめるために、hello_controller.jsを下記のようにしてみましょう。

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  connect() {
    console.log("こんにちは!", this.element)
  }
}

できたら、ブラウザリロードを行い、検証コンソールを開きましょう(chromeであれば右クリックの検証です)。

Google Chrome 検証 コンソール表示抜粋

上記のように表示されたかと思います。これでコントローラが動いていることが確認できました。

イベントをハンドリングする。アクションの設定

そしたら、今度は「こんにちは」ボタンを押したら検証コンソールに表示されるように改造してみましょう。下記のようにします。

まず、Javascriptのconnect()をgreet()にリネームします。

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  greet() {
    console.log("Hello, Stimulus!", this.element)
  }
}

そして、HTMLのbuttonタグにイベントアクションを設定します。
下記のようにします。HTMLファイル全体だと長くなってしまうので抜粋です。

<div data-controller="hello">
  <input type="text">
  <button data-action="click->hello#greet">Greet</button>
</div>


Stimulusではイベントのハンドリングの設定をdata-actionという属性で行います。
data-action属性の値でどのイベントのとき何を呼び出す?という指定を行っています。

“click->hello#greet”をアクションディスクリプタと呼んでいるようですが、ぶっちゃけ名前よりも意味を理解しましょう。

まず”click”はイベントハンドラに対応します。今回はボタンのためclickイベントに対応します。もちろんテキストフィールドなどの別のインプットタグのイベントも使えます。

次に、”->”の右側です。

“hello”はどのコントローラかを指定しています。
そして”#greet”で、コントローラのどのメソッドかを指定しています。

これによりボタンがクリックされたときhelloコントローラのgreetメソッドを呼び出してねと設定できました。

では実際にブラウザをリロードして実行してみましょう。
何度も「こんにちは」ボタンをクリックすると検証コンソールに繰り返し表示されるかと思います。

クリック連打結果

できましたでしょうか?。
ここまでで大体、コントローラとHTMLの接続方法が分かったかと思います。

ターゲット。コントローラ内でDOMを参照する

最後に、インプットフォームに名前を入力して、動的に表示する文字列を変更するようにしてみましょう。

そのためには、インプットフォームの値をコントローラで参照できるようにしなければなりません。
どうやればいいのでしょうか。

Stimulusではコントローラ内でタグを参照するための機能を用意してくれています。

HTMLファイルを下記のように書き換えてみましょう。

<div data-controller="hello">
  <input data-hello-target="name" type="text">
  <button data-action="click->hello#greet">Greet</button>
</div>

inputタグにdata-hello-target属性を付与しました。値をnameとしていますね。
こうすることでコントローラ側で、”name”という名前でプロパティとして参照することができるようになります。”name”がわかりづらいですが、”hoge”でもなんでも自由に指定できます。

コントローラ側を下記のように書き換えてください。

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "name" ]

  greet() {
    const element = this.nameTarget
    const name = element.value
    console.log(`こんにちは!、 ${name}!`)
  }
}

4行目のように、static targets = [ “name” ]と書くことでHTML側で”name”として設定したDOMを参照するよう宣言することができます。Stimulusのお約束です。

“name”という値はhtml側と同一であれば自由な名前で大丈夫です。
また、今回は一つしか作成していませんが、複数作っても大丈夫です。
(複数のタグにdata-hello-target=”name”を設定した場合、設定したタグすべてを取得可能になります。
詳しくは、Stimulusのリファレンスを参照してください。)

宣言することによって、StimulusはそのDOMを参照するためのプロパティを自動で作ってくれます。
自動で作ってくれるプロパティ名は、this.nameTargetのようにthis.○○Targetという形になります。

ここまでできたらリロードして、名前を入力してボタンをクリックしてみましょう。
検証コンソールにこんにちは!、○○と出力されるはずです。

検証コンソール結果

Stimulusのコントローラは単純なJavascriptクラスのインスタンスということ

ここまで、
HTMLとコントローラの接続方法
イベントハンドリングの仕方
DOM参照方法
ということを見てきました。

そして、Stimulusコントローラは単純にJavaScriptクラスのインスタンスであるということを理解できるかと思います。

つまり、JavaScriptのいろいろなテクニックがそのまま使えちゃうということです。
例えば、getterメソッドを使ってリファクタリングしてみましょう。

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "name" ]

  greet() {
    console.log(`Hello, ${this.name}!`)
  }

  get name() {
    return this.nameTarget.value
  }
}

Stimulusフレームワークの主要な機能

コントローラ
イベントアクション
ターゲット

について説明しました。

次回は、コピーペースト機能を作り、もうすこし実践的な使い方をご紹介します。