💬

stimulusでオートコンプリート機能実装

2024/12/05に公開

はじめに

エンジニア転職を目指しRuby on Railsを中心に学習中の初学者です。
備忘録として、躓いたことやケアレスミスも含め投稿します!誤っている箇所などありましたらご指摘いただけると幸いです

対象読者

  • hotwire初学者

stimulusのセットアップ

1.stimulusのインストール

bin/rails stimulus:install
# docker利用の場合
docker compose run(コンテナ起動中は`exec`でも可) web bash

bin/rails stimulus:install

2. jsonファイルの確認

# 下記の記載があるか確認してください。
"@hotwired/stimulus": "^3.2.2"

3. app/javascript/controllersに実装したい機能のコントローラー追加

bin/rails generate stimulus example # `example`は適宜設定(例:オートコンプリート機能を実装したい場合は`autocomplete`等役割がわかる命名をする)

#補足
bin/rails g stimulus example
																#どちらでも可能
rails g stimulus example

オートコンプリート機能

app/javascript/controllers/autocomplete_controller.js

// app/javascript/controllers/autocomplete_controller.js
import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="autocomplete"
export default class extends Controller {
  static values = { url: String }
  static targets = ["results"]

  search(event) {
    const query = encodeURIComponent(event.target.value);  
    const url = `${this.urlValue}?q=${query}`;

    fetch(url)
      .then(response => response.json())
      .then(data => {
        this.updateResults(data);
      })
      .catch(error => console.error('Error fetching autocomplete data:', error));
  }

  updateResults(data) {
    this.resultsTarget.innerHTML = '';

    data.forEach(item => {
      const li = document.createElement('li');
      li.textContent = item.title;  
      li.addEventListener('click', () => {
        this.selectResult(item);
      });
      this.resultsTarget.appendChild(li);
    });
  }

  selectResult(item) {
    this.element.querySelector('input').value = item.title;  

    this.resultsTarget.innerHTML = '';
  }
}

検索フォーム


<!-- ransackなし -->
<%= form_with url: search_examples_path, method: :get, local: true do |form| %>
	<div class="search-bar" data-controller="autocomplete" data-autocomplete-url-value="<%= autocomplete_examples(検索対象にしたいテーブル名)_path %>">
		<%= form.label :query, "検索対象名" %>
		<%= form.search_field :query %>
		<%= form.submit "Search" %>
		<ul data-autocomplete-target="results" class="autocomplete-results"></ul>
	</div>
<% end %>

<!-- ransackあり -->
<%= search_form_for @q, url: url do |f| %>
 <div class="search-bar" data-controller="autocomplete" data-autocomplete-url-value="<%= autocomplete_examples(検索対象にしたいテーブル名)_path %>">
  <%= f.text_field :title_or_decription_cont, class: 'form-control', placeholder: t('.search_word'), data: { action: "input->autocomplete#search" } %>
  <ul data-autocomplete-target="results" class="autocomplete-results"></ul>
 </div>
 <%= f.submit '検索', class: 'btn btn-primary' %>
<% end %>

コントローラーの編集

# ransackなし
def autocomplete
  if params[:title].present?
      @users = User.where('title LIKE ?', "%#{params[:title]}%")
    else
      @users = User.all
    end

  render json: @examples.as_json(only: [:id, :title, :decription])
end

# ransackあり
def autocomplete
  @q = Facility.ransack(params[:q])
  @examples = @q.result(distinct: true).limit(10)

  render json: @examples.as_json(only: [:id, :title, :decription])
end

routes.rb

resources :examples, only: %i[index search(ransack未使用時) show new create update destroy] do
# 下記を設定↓
    collection do
      get :autocomplete
    end

参考資料

https://stimulus.hotwired.dev/handbook/origin
https://zenn.dev/sudoukky/articles/4d4550bdc677be

Discussion