コード例
ここで作成するのはリアルタイム検索です。下記のようなUIです。
デモはこちらに用意しています。
<a>タグや<form>タグのネイティブな動作だけでは不十分です。検索窓(<input>タグ)のinputイベントを捉えないとリアルタイム検索に検索してくれません<input>タグのinputイベントを捉える処理を書く必要があります<input>タグのinputイベントを受け取り、そのまま<form>タグのsubmitをするだけですので、ステートを持つ必要はありません<form>タグのsubmitまでが責務です。したがって制御範囲は<form>タグだけで十分であり、検索結果を制御する必要はありません<% content_for :title, "Customers" %> <div class="max-w-lg mx-auto"> <div class="mb-16"> <h1 class="text-4xl text-center">Customers</h1> </div> <%= render "search" %> <%= turbo_frame_tag "customers" do %> <table class="table table-striped w-full"> <thead> <tr class="border-b-2 border-gray-900"> <th class="p-2 text-left">Name</th> <th class="p-2 text-left">JP Name</th> </tr> </thead> <tbody> <% @customers.each do |customer| %> <tr class="group border-t border-gray-400 [:first-child]:border-none"> <td class="p-2"> <%= customer.name %> </td> <td class="p-2"> <%= customer.jp_name %> </td> </tr> <% end %> </tbody> </table> <% end %> </div>
search partialで分けていますturbo_frame_tag "customers"を設置しています
<div class="max-w-72 mx-auto mb-10"> <%= form_with url: customers_path, method: :get, data: {controller: "autosubmit", autosubmit_wait_value: 300, turbo_frame: "customers"} do %> <div class="mt-2"> <%= search_field_tag :query, params[:query], class: "block w-full rounded-full border-0 px-4 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-orange-600 sm:text-sm/6", placeholder: "検索", data: { action: "input->autosubmit#submitWithDebounce" } %> </div> <% end %> </div>
data: {controller: "autosubmit"}のところでautosubmit Stimulus Controllerと接続しています
autosubmit_wait_value: 300でリアルタイム検索をするときのdebounceの待ち時間を設定しています turbo_frame: "customers"により、サーバからのレスポンスはTurbo Frameのid="customers"のところに入れように指示していますsearch_field_tagは検索窓の<input type="search">を作りますが、そこにはdata: { action: "input->autosubmit#submitWithDebounce"が属性としてついています
inputタグのinputイベントを受け取ると、autosubmit Stimulus ControllerのsubmitWithDebounce()が呼ばれる仕組みになっていますimport {Controller} from "@hotwired/stimulus" import {debounce} from "../utilities/utilities" // Connects to data-controller="autosubmit" export default class extends Controller { static values = {wait: {type: Number, default: 300}} connect() { } submit() { this.element.form.requestSubmit() } submitWithDebounce() { debounce(() => this.submit(), this.waitValue)() } }
debounceを使っていますが、これはapp/javascript/utilities/utilities.jsに配置しています。今回は解説しません。static values =ではdebounce処理の待ち時間(wait)を設定しています。デフォルトは300msですが、HTML属性のdata-autosubmit-wait-value="..."を設定すれば自由に変えられますsubmit()がメインの処理です。単にformに対してrequestSubmit()を読んでいるだけですsubmitWithDebounce()はdebounce処理を施したsubmit()を実行するものです
<a>タグのクリックや<form>内の<button>押下には反応しますが、それ以外のイベントに呼応するときはStimulusを使います<input>タグのフォーカス)realtime-searchのようにせず、最初からautosubmitにしていますが、これはそのためです。検索以外の用途でも使えるような名前にしています