[Rails][Tagify]タグのオートコンプリート
はじめに
タグの入力フォームにTagify
を使ってオートコンプリートを追加していきます。
タグのCRUD機能はすでに実装されています。
demoサイト:
環境
Rails 7.0.7
ruby 3.2.1
流れ
- Tagの検索機能を作る
- Tagifyをインストールする
- Tagifyを初期化する
import Tagify from '@yaireo/tagify'
var tagify = new Tagify(...)
- タグ用stimulusコントローラーを作成する
- テキストエリアに
data-controller="tag"
を追加しstimulusと連結させる - タグの検索結果をTagifyに渡し、フロントで表示させる
- タグの入力値をRailsに送信する
Tagの検索機能を作る
ユーザーが文字を入力したら、検索クエリを実行しDB内に関連するタグを返して、ユーザーに表示させるようにします。
Tagの検索URLを追加する
resources :tags, only: %i[index show] do
collection do
get :search
end
end
searchアクションを作成する
class TagsController < ApplicationController
def search
query = params[:query]
@tags = Tag.where("name LIKE ?", "%#{query}%")
# 値を取得する
@tags = @tags.pluck(:name)
render json: @tags
end
end
Tagifyのデフォルトの文字列のフォーマットはJSONになるのでJSONをrenderします。
line
を入力して関連するタグを取得してみます。
23:44:29 web.1 | Started GET "/tags/search?query=line" for ::1 at 2023-08-31 23:44:29 +0900
23:44:29 web.1 | Processing by TagsController#search as */*
23:44:29 web.1 | Parameters: {"query"=>"line"}
23:44:29 web.1 | User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 7], ["LIMIT", 1]]
23:44:29 web.1 | ↳ app/controllers/application_controller.rb:30:in `set_notification_object'
23:44:29 web.1 | Tag Load (0.2ms) SELECT "tags".* FROM "tags" WHERE (name LIKE '%line%')
23:44:29 web.1 | ↳ app/controllers/tags_controller.rb:17:in `search'
23:44:29 web.1 | Completed 200 OK in 6ms (Views: 1.9ms | ActiveRecord: 0.4ms | Allocations: 3238)
23:44:29 web.1 |
23:44:29 web.1 |
ブラウザーのレスポンスはこちらになります:
レコードを取得できましたが、タグ名だけの配列が欲しいのでpluck
メソッドを使ってタグの値を抽出します。
タグの検索機能ができました。
次にTagifyのインストールと設定を行います。
Tagifyをインストールする
インストール方法は公式ドキュメントまでご参考ください。
npm i @yaireo/tagify --save
@import "@yaireo/tagify/dist/tagify.css"
@import "@yaireo/tagify/src/tagify.scss"
Stimulusコントローラーを作成する
bin/rails g stimulus tag
create app/javascript/controllers/tag_controller.js
import { Controller } from "@hotwired/stimulus"
import Tagify from '@yaireo/tagify'
// Connects to data-controller="tag"
export default class extends Controller {
connect() {
var input = document.getElementById("tags-input");
console.log(input);
new Tagify(input);
}
}
データ属性を追加する
textarea
にIDとコントローラー情報を追加します。
クラス名にtagify
を追加するとデフォリトのCSSを表示されます。
...
<%= form.text_area :tag_names,
id: "tags-input",
value: item.tags.map(&:name),
placeholder: '[Enter]キーで区切って入力してください',
class: "tagify"
data: { controller: "tag" } %>
Tagifyを導入したことを確認します。
次はオートコンプリート機能です。
ユーザーの入力によるタグの検索結果をTagifyのwhitelist
に入れていきます。
タグを取得するリクエストを追加する
ドキュメントにサンプルコードがあるのでそのまま持ってきます。
import { Controller } from "@hotwired/stimulus"
import Tagify from '@yaireo/tagify'
// Connects to data-controller="tag"
export default class extends Controller {
connect() {
var input = document.getElementById("tags-input");
// tagifyの設定
var tagify = new Tagify(input, {whitelist:[],
dropdown:{
enabled: 0,
closeOnSelect: false,
},
}),
controller; // for aborting the call
// 入力で検索結果を取得する
tagify.on('input', onInput)
function onInput( e ){
var value = e.detail.value
tagify.whitelist = null // whitelistをリセットする
controller && controller.abort()
controller = new AbortController()
fetch(`/tags/search?query=${value}`, {signal:controller.signal})
.then(RES => RES.json())
.then(function(newWhitelist){
tagify.whitelist = newWhitelist // ホワイトリストに代入する
tagify.loading(false).dropdown.show(value) // 関連する結果を表示させる
})
}
}
}
取得されたタグをフロントで表示できるようになりました。
タグの送信
タグがハッシュの配列として保存されるので値だけを抽出しRailsに送ります。
Tagifyではtagify.DOM.originalInput.value
メソッドが用意してくれてます。
console.log(tagify.DOM.originalInput.value)
=> ruby,rails
console.log(tagify.DOM.originalInput.value.split(','))
=> (2) ['ruby', 'rails']
0: "ruby"
1: "rails"
length: 2
[[Prototype]]: Array(0)
...
var tagify = new Tagify(input, {whitelist:[],
dropdown:{
enabled: 0,
classname: "",
closeOnSelect: false,
},
# 値だけ取得する
originalInputValueFormat: valuesArr => valuesArr.map(item => item.value)
}),
終わりに
ライブラリーを使うことでタグのオートコンプリートができました。
ドキュメントが分かりやすかったので助かりました。
他にカスタマイズできるオプションやテンプレもたくさんあるのでまた試してみたいと思います。
Discussion