shimoharuki / usj_app

0 stars 0 forks source link

オートコンプリート機能について #22

Closed shimoharuki closed 1 year ago

shimoharuki commented 1 year ago

いつもお世話になっております オートコンプリート機能作成中

手詰まりしているのでご教授お願いしたいです

発生している問題

github公開されているオートコンプリート機能のフレームワークを使用したかったのですが jsの理解が乏しかったため jsの勉強も兼ねて自分で1から実装しました

header.js

document.addEventListener('DOMContentLoaded', () => {

    const jsSeacrchForm = document.getElementById('search-form')
    const jsConversion = document.querySelector("#conversion")
    jsSeacrchForm.addEventListener('input', async () => {
        const inputValue = jsSeacrchForm.value;

        // 予測変換の結果を取得する非同期処理(例としてダミーデータを使用)
        const predictions = await fetchPredictions(inputValue);

        // 予測変換の結果を HTML に変換して表示する
        const html = predictions.map(board => {
            return `<li><a href="/boards/${board.id}">${board.title}</a></li>`;
        }).reduce((a, b) => {
            return a + b
          })  

        jsConversion.innerHTML = html;
      });

      async function fetchPredictions(inputValue) {
        // 予測変換の結果を取得する非同期処理を実装する
        const response = await fetch('/boards.json');
        const data = await response.json();

        // 入力文字列と部分一致する board をフィルタリングする
        const matchedBoard = data.filter(board => board.title.includes(inputValue)).slice(0, 3);
        console.log(data)

        return matchedBoard;
      }
});

こちらのコードを作成し、 文字列が部分一致する投稿を取得しリンクにしてhtml内に表示 するメソッドを作成したのですが

const response = await fetch('/boards.json');のfetchが一度に取得できる数に限りがあると後で気づき

header.js

document.addEventListener('DOMContentLoaded', () => {
    const jsSearchForm = document.getElementById('search-form');
    const jsConversion = document.querySelector("#conversion");

    jsSearchForm.addEventListener('input', async () => {
      const inputValue = jsSearchForm.value;

      // 予測変換の結果を取得する非同期処理(例としてダミーデータを使用)
      const predictions = await fetchPredictions(inputValue);

      // 予測変換の結果を HTML に変換して表示する
      const html = predictions
        .map(board => `<li><a href="/boards/${board.id}">${board.title}</a></li>`)
        .reduce((a, b) => a + b, "");

      jsConversion.innerHTML = html;
    });

    async function fetchPredictions(inputValue) {
      // 全記事を取得するための非同期処理
      const allBoards = await fetchAllBoards();

      // 入力文字列と部分一致する board をフィルタリングする
      const matchedBoard = allBoards
        .filter(board => board.title.includes(inputValue))
        .slice(0, 3);

      return matchedBoard;
    }

    async function fetchAllBoards() {
      let allBoards = [];
      let page = 1;
      let limit = 10; // 1回の取得での記事数の上限

      while (true) {
        const response = await fetch(`/boards.json?page=${page}&limit=${limit}`);
        const data = await response.json();

        if (data.length === 0) {
          // 取得できる記事がなくなったらループを終了
          break;
        }

        // 取得した記事を逆順に追加していく
        allBoards = data.concat(allBoards);
        page++;
      }

      return allBoards;
    }
  });

全記事を取得するまでループする処理を記述した コードにしたのですが

サーバーがとてつもなく重くなってしまいました。

全記事をサーバーを重くすることなく取得するコードにしたいのですが調べてもあまり出てこずで 詰まっているので教えていただきたいです。

関連のあるコード

header.html.erb

 <header>
<%= javascript_include_tag 'header' %>
  <nav class="navbar navbar-expand-lg navbar-light text-dark bg-dark py-4" id="home">
      <%= link_to 'MagicalUsj', root_path, class: 'navbar-brand h1 text-white' %>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <%= render 'boards/search', q: @q, url: boards_path %>
    <div class="collapse navbar-collapse" id="navbarNav">
      <ul class="navbar-nav">
        <li class="nav-item active">
          <%= link_to 'お気に入り', likes_boards_path , class: "nav-link text-white" %>
        </li>
        <li class="nav-item">
          <%= link_to 'おすすめ', recommendations_path, method: :post, class: 'nav-link text-white' %>
        </li>
        <li class="nav-item">
          <%= link_to 'MyPage', profile_path, class: "nav-link text-white" %>
        </li>
        <li class="nav-item dropdown">
        <%= link_to '記事', boards_path , class: "nav-link dropdown-toggle text-white", id: "navbarDropdown", role: "button", "data-toggle": "dropdown", "aria-haspopup": "true", "aria-expanded": "false" %>
        <div class="dropdown-menu" aria-labelledby="navbarDropdown">
          <%= link_to 'パーク', main_index_path , class: "dropdown-item" %>
          <%= link_to 'イベント', boards_path(tag_name: 'event'), class: "dropdown-item" %>
          <%= link_to '困った時', boards_path(tag_name: 'question'), class: "dropdown-item" %>
          <%= link_to '入場までの準備', boards_path(tag_name: 'preparation'), class: "dropdown-item" %>
      </li>
        <li class="nav-item">
          <%= link_to 'ログアウト', logout_path, class: 'nav-link text-white', method: :delete %>
        </li>
      </ul>
    </div>
  </nav>
</header>

search.html.erb

<div class="form-inline">
    <div class="form-group mr-2">
    <%= search_form_for @search, url: url do |f| %>
        <%= f.search_field :title_or_body_cont, id: 'search-form', class: 'form-control', placeholder: '検索ワード' %>
        <%= f.submit '検索', class: 'btn btn-primary' %>
    <% end %>
    </div>
</div>

主に参考にした資料

https://www.youtube.com/live/t6M00cRjEA8?feature=share

Tsuchiya2 commented 1 year ago

以下参考にして調べたり色々してみてください。


マルチ検索・オートコンプリート 概要: 食べログの検索フォームのような、様々なカラムから検索可能な検索フォームです。1文字入力するたびに、候補が表示されるため、ユーザーの入力手間を減らし、入力ミスを減らすことができます。

使用技術・ライブラリ: