RailsアプリにChoices.jsを使ったセレクトボックスを作る

## 概要
Choices.jsを使ってセレクトボックスを作成しました

## はじめに
現在、[フィヨルドブートキャンプ](https://bootcamp.fjord.jp/)でチーム開発をしています。
[Choices.js](https://github.com/Choices-js/Choices)というライブラリを使って、セレクトボックスを作成しましたが、情報が少なかったのでQiitaに記事として残しておきます。
初学者向けの内容となっています。

## Choices.jsについて
軽量な選択ボックス/テキスト入力プラグインです。リッチなセレクトボックスが作れます→[DEMO](https://choices-js.github.io/Choices/)
Select2およびSelectizeに似ていますが、jQueryの依存関係はありません。
2年ほどリリースが止まっていたようですが、2021年の12月より再びメンテナンスされているようです。

## インストール
- npm
```
npm install choices.js
```
- yarn
```
yarn add choices.js
```
- stylesheet
導入したらしっかりstylesheetで読み込みましょう。
自分はこれを忘れて無駄な時間を過ごしてしまいました😅(忘れるのは初学者の自分だけだと思います)
CDNは以下、その他ディレクトリで読み込むものなど多数あります(README参照)
```
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/choices.js@9.0.1/public/assets/styles/choices.min.css"/>
```

## 用語
専門用語というほどではないんですが、ここを読み解かないとうまく使いこなせませんでした。
ほとんどREADMEを翻訳したものだけど載せておきます。
（今回はセレクトボックスを作るので、テキストボックスとしての使い方は割愛）
|用語|説明|
|:--|:--|
|Choice|ユーザーが実際に選択できる値で、`<option>`要素と同等 |
|Group|選択肢の集まりでその名の通りグループ。`<optgroup>`要素と同等|
|Item|選択された要素の`<option value = "item">`要素と同等|

HTMLでのセレクトボックスはというと
```html
<select name="spice">
 <option value="">スパイスを選択</option>
 <option value="garammasala">ガラムマサラ</option>
 <option value="coriander">コリアンダー</option>
 <option value="cumin">クミン</option>
</select>
```
となっているのでChoiceは`<option>`のこと、Itemは`<option>`の`value`だとわかります。

ということでChoices.jsを使って、もっとも簡単だと思われるコードを書いてみました
```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>Spice select</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/choices.js@9.0.1/public/assets/styles/choices.min.css"
      />
    <script src="https://cdn.jsdelivr.net/npm/choices.js@9.0.1/public/assets/scripts/choices.min.js"></script>
  </head>
  <body>
    <select name="spice" id="hoge">
      <option value="">スパイスを選択</option>
      <option value="garammasala">ガラムマサラ</option>
      <option value="coriander">コリアンダー</option>
      <option value="cumin">クミン</option>
    </select>
    <script>
      document.addEventListener("DOMContentLoaded", () => {
        new Choices("#hoge")
      })
    </script>
  </body>
</html>
```
![Choices.js demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/936472/e7b15e85-97ac-c647-d972-d61e136b81dc.gif)
セレクトボックスに`hoge`というidを振って、Choicesオブジェクトを作る際に紐づけるだけです。
これでインクリメンタルサーチが簡単に使えるし、上の通りvalue属性でもヒットします。
選択肢が多くなったときに便利ですね。

開発者ツールを見てみると`class="choices"`や`data-type="select-one"`などのタグが使われています。
`<select>`は**select-one**、`<select multiple>`と**select-multiple**となっていて、
[オプション](https://github.com/Choices-js/Choices#configuration-options)が反映できるか否かは、この入力タイプを確認するとわかりやすいと思います。

## Railsでの使い方
再び簡単な復習になるんですが、既にSpiceモデルがあるとして、[select](https://railsdoc.com/page/select)を使うと
```ruby
select(:spice, :name, Spice.pluck(:name, :id), { include_blank: "スパイスを選択" })
```
[collection\_select](https://railsdoc.com/page/collection_select)を使うと
```ruby
collection_select(:spice, :name, Spice.all, :id, :name, prompt: "スパイスを選択")
```
これをHTMLで出力すると、いずれも
```html
<select name="spice[name]" id="spice_name">
　　<option value="">スパイスを選択</option>
　　<option value="1">ガラムマサラ</option>
　　<option value="2">コリアンダー</option>
　　<option value="3">クミン</option>
</select>
```
のようになります。
こちらもこのセレクトボックスにidさえ付与すれば、Choices.jsが使用可能です。

ここからは実際に自分がチーム開発で実装したコードに、一部修正を加えたものを記載していきます。
### 環境とgem
- ruby 3.1.0
- Rails 6.1.4.4
- webpacker 5.4.3
- Choices.js
- slim-rails

UserモデルとSpiceモデルが存在し、UserはSpice(好みのスパイス)を1つ持つような関係です。
CSSに関してはnode_modulesから読み込むように設定しています。

### view
```slim
= f.label :spice, class: 'a-form-label'
= f.collection_select :spice_id, all_spices_with_empty, :id, :name, {}, { id: 'js-spice-select' }
```
フォーム内でのセレクトボックスです。
セレクトボックスに`js-spice-select`というidを付与しています。
`all_spices_with_empty`は選択肢なしを含めた配列です。
``` ruby
def all_spices_with_empty
  Spice.all.to_a.unshift(Spice.new(name: '好みのスパイスなし'))
end
```

### javascript
```javascript:app/javascript/packs/application.js
import '../spice-select.js'
```
JavaScriptファイルをWebpacker経由で読み込んでいます。

```javascript:app/javascript/spice-select.js
import Choices from 'choices.js'

document.addEventListener('DOMContentLoaded', () => {
  const element = document.getElementById('js-spice-select')
  if (element) {
    return new Choices(element, {
      removeItemButton: true,
      allowHTML: true,
      searchResultLimit: 10,
      searchPlaceholderValue: '検索ワード',
      noResultsText: '一致する情報は見つかりません',
      itemSelectText: '選択'
    })
  }
})
```
以上のように、少しだけオプションをつけてみます。
`allowHTML`オプションをつけないと、以下のようなwarningが出ます。
```
Deprecation warning: allowHTML will default to false in a future release. 
To render HTML in Choices, you will need to set it to true. 
Setting allowHTML will suppress this message.
```
また、Choices.js関連の要素がなければ、下記のコンソールエラーが出てしまうのでif文を使っています。
```
Uncaught TypeError: Expected one of the following types text|select-one|select-multiple
```

と、ここまで作り終えたところで
![Choice.js demo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/936472/64a096ee-3ab3-44a8-da88-18ae4713ee73.gif)
Choices.jsを使ったセレクトボックスが完成しました🎉

これがRailsでChoices.jsを使う初歩的な方法だと思います。
他にも選択肢を他からfetchして作成したり、複数の選択肢を選んだり、タグをつけたり、、、
などなどカスタマイズが可能なので、少しリッチなセレクトボックスを作成するのにいかがでしょうか？

## 最後に
最後までご覧いただきありがとうございました。本記事がどなたかのご参考になれば幸いです。
何かご意見やご感想などありましたら、お気軽にコメントや編集リクエストをお待ちしております🙏

## 参考文献
執筆にあたり、以下の記事を参考とさせていただきました。ありがとうございました🙇‍♂️

https://qiita.com/DevNururi/items/83818eb8380c06610314

https://qiita.com/hirocueki2/items/e04e5ef11d18607c9cb3