Stimulus 3: リアルなものを構築する

:::note
この記事は[Google翻訳](https://translate.google.co.jp/)の結果を編集したものです。
:::

https://stimulus.hotwired.dev/handbook/building-something-real

最初のコントローラーを実装し、StimulusがHTMLをJavaScriptに接続する方法を学びました。 それでは、Basecampからコントローラーを再作成して、実際のアプリケーションで使用できるものを見てみましょう。

# DOMクリップボードAPIのラッピング

BasecampのUIには次のようなボタンが散在しています。

![bc3-clipboard-ui.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2238166/a07f03d3-3a96-7438-dfc1-3089312c16df.png)

これらのボタンのいずれかをクリックすると、BasecampはURLや電子メー アドレスなどのテキストをクリップボードにコピーします。

WebプラットフォームにはシステムクリップボードにアクセスするためのAPIがありますが、必要なことを行うHTML要素はありません。"クリップボードにコピー"ボタンを実装するにはJavaScriptを使用する必要があります。

# コピーボタンの実装

PINを生成して他のユーザーにアクセスを許可できるアプリがあるとします。生成されたPINをボタンと一緒に表示して、簡単に共有できるようにクリップボードにコピーできれば便利です。

`public/index.html`を開き`<body>`の内容をボタンのラフスケッチに置き換えます。

```html
<div>
  PIN: <input type="text" value="1234" readonly>
  <button>Copy to Clipboard</button>
</div>
```

# コントローラーのセットアップ

次に`src/controllers/clipboard_controller.js`を作成し、空のメソッド`copy()`を追加します。

```javascript
// src/controllers/clipboard_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  copy() {
  }
}
```

次に外側の`<div>`に`data-controller="clipboard"`を追加します。この属性が要素に表示されるたびに、Stimulusはコントローラーのインスタンスを接続します。

```html
<div data-controller="clipboard">
```

# ターゲットの定義

クリップボードAPIを呼び出す前にその内容を選択できるように、テキストフィールドへの参照が必要です。テキストフィールドに`data-clipboard-target="source"`を追加します。

```html
PIN: <input data-clipboard-target="source" type="text" value="1234" readonly>
```

コントローラーにターゲット定義を追加して、テキストフィールド要素に`this.sourceTarget`としてアクセスできるようにします。

```javascript
export default class extends Controller {
  static targets = [ "source" ]

  // ...
}
```

## 静的ターゲットラインとは何ですか?

Stimulusがコントローラークラスをロードするとき、`target`と呼ばれる静的配列でターゲット名の文字列を探します。配列内のターゲット名ごとにStimulusは3つの新しいプロパティをコントローラーに追加します。ここで、`"source"`ターゲット名は次のプロパティになります。

- `this.sourceTarget`はコントローラーのスコープ内の最初の`source`ターゲットに評価されます。`source`ターゲットがない場合、プロパティにアクセスするとエラーがスローされます。
- `this.sourceTargets`は、コントローラーのスコープ内のすべての`source`ターゲットの配列に評価されます。
- `this.hasSourceTarget`は`source`ターゲットがある場合は`true`に評価され、そうでない場合は`false`に評価されます。

ターゲットの詳細については[リファレンスドキュメント](https://stimulus.hotwired.dev/reference/targets)を参照してください。

# アクションの接続

これでコピーボタンを接続する準備が整いました。

ボタンをクリックしてコントローラーの`copy()`メソッドを呼び出す必要があるため、`data-action="clipboard#copy"`を追加します。

```html
<button data-action="clipboard#copy">Copy to Clipboard</button>
```

## 一般的なイベントには省略形のアクション表記があります

アクション記述子から`click->`を省略したことに気付いたかもしれません。これはStimulusがクリックを`<button>`要素のアクションのデフォルトイベントとして定義しているためです。

他の特定の要素にもデフォルトのイベントがあります。 完全なリストは次のとおりです。

| 要素 | デフォルトイベント |
|:---|:---|
| a | click |
| button | click |
| details | toggle |
| form | submit |
| input | input |
| input type=submit | click |
| select | change |
| textarea | input |

最後に`copy()`メソッドで入力フィールドの内容を選択し、クリップボードAPIを呼び出します。

```javascript
copy() {
  navigator.clipboard.writeText(this.sourceTarget.value)
}
```

ブラウザにページをロードし、コピーボタンをクリックします。 次にテキストエディターに戻って貼り付けます。PIN`1234`が表示されます。

# Stimulusコントローラーは再利用可能

これまで一度に1つのコントローラーのインスタンスがページ上にある場合に何が起こるかを見てきました。

ページ上にコントローラーの複数のインスタンスが同時に存在することは珍しくありません。たとえばPINのリストを表示し、それぞれに独自のコピーボタンを表示したい場合があります。

私たちのコントローラーは再利用可能です。テキストの一部をクリップボードにコピーする方法を提供したいときはいつでも、必要なのはページに適切な注釈を付けてマークアップすることだけです。

ページに別のPINを追加してみましょう。`<div>`をコピーして貼り付け、2つの同一のPINフィールドが存在するようにし、2番目の`value`属性を変更します。

```html
<div data-controller="clipboard">
  PIN: <input data-clipboard-target="source" type="text" value="3737" readonly>
  <button data-action="clipboard#copy">Copy to Clipboard</button>
</div>
```

ページを再読み込みして、両方のボタンが機能することを確認します。

# アクションとターゲットはあらゆる種類の要素に適用できます

次にPINフィールドをもう1つ追加しましょう。 今回はボタンの代わりにコピーリンクを使用します。

```html
<div data-controller="clipboard">
  PIN: <input data-clipboard-target="source" type="text" value="3737" readonly>
  <a href="#" data-action="clipboard#copy">Copy to Clipboard</a>
</div>
```

Stimulusでは適切な`data-action`属性を持っている限り、必要なあらゆる種類の要素を使用できます。

この場合、リンクをクリックするとブラウザーもリンクの`href`をたどることになることに注意してください。アクションで`event.preventDefault()`を呼び出すことで、このデフォルトの動作をキャンセルできます。

```javascript
copy(event) {
  event.preventDefault()
  navigator.clipboard.writeText(this.sourceTarget.value)
}
```

同様に`source`ターゲットは`<input type="text">`である必要はありません。コントローラーは`value`プロパティと`select()`メソッドを持つことだけを想定しています。 つまり、代わりに`<textarea>`を使用できます。

```html
PIN: <textarea data-clipboard-target="source" readonly>3737</textarea>
```

# まとめと次のステップ

この章ではブラウザーAPIをStimulusコントローラーにラップする実際の例を見てきました。コントローラーの複数のインスタンスが一度にページに表示される方法を確認し、アクションとターゲットがHTMLとJavaScriptの疎結合を維持する方法を調べました。

次にコントローラーの設計を少し変更するだけで、より堅牢な実装につながる方法を見てみましょう。