LoginSignup
0
0
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

CloudFlareにデプロイするためのRemixプロジェクトで別画面で一覧の検索条件を付与する

Last updated at Posted at 2024-06-17

概要

下記でクエリパラメーターの値に伴って一覧に表示する項目を絞り込む処理を作成した。
今回は別画面で一覧に表示する条件を設定し、一覧画面に遷移させてみようと思う。

詳細

トップページに検索条件を選択するウインドウ的なものを用意し、検索条件を入力後「検索する」ボタンを押下するとクエリパラメーターが入った状態の一覧画面に遷移させたい。

前提

下記記事の内容が完了していること

方法

トップ画面/から/tasksに遷移するボタンの設置

まずは下記の方法でトップ画面からクエリパラメーター無しの/tasksに遷移するボタンを設置する。

  1. app/routes/_index.tsxを下記のように修正し、ボタンを設置

    app/routes/_index.tsx
    import type { MetaFunction } from "@remix-run/cloudflare";
    import { useNavigate } from "@remix-run/react";
    
    export const meta: MetaFunction = () => {
      return [
        { title: "Top" },
        {
          name: "description",
          content: "Top",
        },
      ];
    };
    
    export default function Index() {
      const navigate = useNavigate();
    
      const handleSearchClick = () => {
        navigate("/tasks"); // 一覧画面に遷移
      };
    
      return (
        <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
          <div>
            <h2>タスク管理</h2>
            <button onClick={handleSearchClick}>検索する</button>
          </div>
        </div>
      );
    }
    
  2. npm run devを行い、トップ画面にアクセスし「登録する」をクリックし、クエリパラメーターがついていない一覧が表示されることを確認

    CleanShot 2024-06-16 at 12.14.58.gif

  3. app/routes/_index.tsxを下記のように修正し、一旦クエリパラメーターをハードコーディング

    app/routes/_index.tsx
    import type { MetaFunction } from "@remix-run/cloudflare";
    import { useNavigate } from "@remix-run/react";
    
    export const meta: MetaFunction = () => {
      return [
        { title: "Top" },
        {
          name: "description",
          content: "Top",
        },
      ];
    };
    
    export default function Index() {
      const navigate = useNavigate();
    
      const handleSearchClick = () => {
        navigate("/tasks?isDeleted=true"); // 遷移先ページ指定
      };
    
      return (
        <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
          <div>
            <h2>タスク管理</h2>
            <button onClick={handleSearchClick}>検索する</button>
          </div>
        </div>
      );
    }
    
  4. トップ画面にアクセスし「登録する」をクリックし、isDeleted=trueクエリパラメーターがついている一覧が表示されることを確認

    CleanShot 2024-06-16 at 12.19.38.gif

絞り込み内容を入力する場所の追加

一気に複数項目の絞り込みメニューを作ると複雑になりそうなのでまずはisDeletedだけを絞り込むフィールドを追加してみる。

  1. app/routes/_index.tsxを下記のように修正し、削除済みタスクだけを絞り込むフィールドを追加

    app/routes/_index.tsx
    import type { MetaFunction } from "@remix-run/cloudflare";
    import { useNavigate } from "@remix-run/react";
    import { useState } from "react";
    
    export const meta: MetaFunction = () => {
      return [
        { title: "Top" },
        {
          name: "description",
          content: "Top",
        },
      ];
    };
    
    export default function Index() {
      const navigate = useNavigate();
      const [isDeleted, setIsDeleted] = useState(false);
    
      const handleSearchClick = () => {
        const queryParams = new URLSearchParams({ isDeleted: isDeleted.toString() });
        navigate(`/tasks?${queryParams.toString()}`); // クエリパラメーターを含めて遷移
      };
    
      return (
        <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
          <div>
            <h2>タスク管理</h2>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isDeleted}
                  onChange={(e) => setIsDeleted(e.target.checked)}
                />
                削除済みを表示
              </label>
            </div>
            <button onClick={handleSearchClick}>検索する</button>
          </div>
        </div>
      );
    }
    
  2. トップ画面にアクセスし、「削除済みを表示」のチェックボックスをチェックつけたり、外したりして「登録する」をクリックし、isDeleted=trueクエリパラメーターのtrueやfalseが設定されて、一覧が表示されることを確認

    CleanShot 2024-06-16 at 12.44.12.gif

  3. 今は「チェックボックスがONでもOFFでも、必ずクエリパラメーターがtrueかfalseで付与」されるがapp/routes/_index.tsxを下記のように修正することで「チェックボックスがONの場合だけ、クエリパラメーターのtrueを付与」というように実装が可能。要件にもよるがURLがシンプルになるので筆者はこちらを選択(表示内容は変化しないようにtasks-loader.tsを記載しているので変わらない)(URLがシンプルになる分、_index.tsxのコードが若干複雑になる)

    app/routes/_index.tsx
    import type { MetaFunction } from "@remix-run/cloudflare";
    import { useNavigate } from "@remix-run/react";
    import { useState } from "react";
    
    export const meta: MetaFunction = () => {
      return [
        { title: "Top" },
        {
          name: "description",
          content: "Top",
        },
      ];
    };
    
    export default function Index() {
      const navigate = useNavigate();
      const [isDeleted, setIsDeleted] = useState(false);
    
      const handleSearchClick = () => {
        const queryParams = new URLSearchParams();
        if (isDeleted) {
          queryParams.append("isDeleted", isDeleted.toString());
        }
        navigate(`/tasks?${queryParams.toString()}`); // クエリパラメーターを含めて遷移
      };
    
      return (
        <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
          <div>
            <h2>タスク管理</h2>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isDeleted}
                  onChange={(e) => setIsDeleted(e.target.checked)}
                />
                削除済みを表示
              </label>
            </div>
            <button onClick={handleSearchClick}>検索する</button>
          </div>
        </div>
      );
    }
    
  4. 下記のような挙動になる。「チェックボックスつけたときだけクエリパラメーターが付与」されているところに注目

    CleanShot 2024-06-16 at 12.48.44.gif

「完了可否」の検索条件の入力フィールドを追加

  1. app/routes/_index.tsxを下記のように修正し、「完了可否」の検索条件入力フィールドとクエリパラメーターの作成部分を追加

    app/routes/_index.tsx
    import type { MetaFunction } from "@remix-run/cloudflare";
    import { useNavigate } from "@remix-run/react";
    import { useState } from "react";
    
    export const meta: MetaFunction = () => {
      return [
        { title: "Top" },
        {
          name: "description",
          content: "Top",
        },
      ];
    };
    
    export default function Index() {
      const navigate = useNavigate();
      const [isDeleted, setIsDeleted] = useState(false);
      const [isComplete, setIsComplete] = useState(false);
    
      const handleSearchClick = () => {
        const queryParams = new URLSearchParams();
        if (isDeleted) {
          queryParams.append("isDeleted", isDeleted.toString());
        }
        if (isComplete) {
          queryParams.append("isComplete", isComplete.toString());
        }
        navigate(`/tasks?${queryParams.toString()}`); // クエリパラメーターを含めて遷移
      };
    
      return (
        <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
          <div>
            <h2>タスク管理</h2>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isDeleted}
                  onChange={(e) => setIsDeleted(e.target.checked)}
                />
                削除済みを表示
              </label>
            </div>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isComplete}
                  onChange={(e) => setIsComplete(e.target.checked)}
                />
                完了済みを表示
              </label>
            </div>
            <button onClick={handleSearchClick}>検索する</button>
          </div>
        </div>
      );
    }
    
  2. 動作確認は最後にまとめて実施予定

「タスクカテゴリ」の検索条件の入力フィールドを追加

「タスクカテゴリ」は複数項目存在するのでプルダウンで入力フィールドを用意する

  1. app/routes/_index.tsxを下記のように修正し、「タスクカテゴリ」の検索条件入力フィールドとクエリパラメーターの作成部分を追加

    app/routes/_index.tsx
    import type { MetaFunction } from "@remix-run/cloudflare";
    import { useNavigate } from "@remix-run/react";
    import { useState } from "react";
    
    export const meta: MetaFunction = () => {
      return [
        { title: "Top" },
        {
          name: "description",
          content: "Top",
        },
      ];
    };
    
    export default function Index() {
      const navigate = useNavigate();
      const [isDeleted, setIsDeleted] = useState(false);
      const [isComplete, setIsComplete] = useState(false);
      const [taskCategoryMasterId, setTaskCategoryMasterId] = useState(""); // 初期値を空文字列として定義
    
      const handleSearchClick = () => {
        const queryParams = new URLSearchParams();
        if (isDeleted) {
          queryParams.append("isDeleted", isDeleted.toString());
        }
        if (isComplete) {
          queryParams.append("isComplete", isComplete.toString());
        }
        if (taskCategoryMasterId !== "") {
          queryParams.append("taskCategoryMasterId", taskCategoryMasterId.toString());
        }
        navigate(`/tasks?${queryParams.toString()}`); // クエリパラメーターを含めて遷移
      };
    
      return (
        <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
          <div>
            <h2>タスク管理</h2>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isDeleted}
                  onChange={(e) => setIsDeleted(e.target.checked)}
                />
                削除済みを表示
              </label>
            </div>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isComplete}
                  onChange={(e) => setIsComplete(e.target.checked)}
                />
                完了済みを表示
              </label>
            </div>
            <div>
              <label>
                タスクカテゴリ:
                <select
                  onChange={(e) => setTaskCategoryMasterId(e.target.value)}
                  defaultValue=""
                >
                  <option value="" disabled>選択してください</option>
                  <option value="1">仕事</option>
                  <option value="2">勉強</option>
                  <option value="3">その他</option>
                </select>
              </label>
            </div>
            <button onClick={handleSearchClick}>検索する</button>
          </div>
        </div>
      );
    }
    
  2. これだと「タスクカテゴリが仕事 かつ 勉強」という設定ができないが、それは次の記事で実装予定

ココまでの動作確認

  1. トップを開き「完了済みを表示」にチェックを入れてクエリパラメーターが正常に入ること、一覧表示が正常なことを確認

    CleanShot 2024-06-16 at 13.16.01.gif

  2. トップを開き「タスクカテゴリ」を選びクエリパラメーターが正常に入ること、一覧表示が正常なことを確認

    CleanShot 2024-06-16 at 13.17.28.gif

  3. 最後に複合的な条件で検索を行い、クエリパラメーターが問題なく表示されれば一旦ココまでは完了

タスクカテゴリプルダウンをテーブルから取得した情報で表示する

現状、タスクカテゴリのプルダウンの要素はハードコーディングされている。これだとtasks_category_mastersテーブルに要素を追加してもこのプルダウンの要素は増えない。
そのためプルダウンの要素をtasks_category_mastersテーブルから取得した要素を表示するように変更する。

  1. app/routes/task-category-masters-loader.tsのファイルを作成し下記のように記載

    app/routes/task-category-masters-loader.ts
    import type { LoaderFunctionArgs} from "@remix-run/cloudflare";
    
    export const loader = async ({ context }: LoaderFunctionArgs) => {
      try {
        return await context.db.task_category_masters.findMany();
      } catch (error) {
        console.error("Failed to load users:", error);
        throw new Response("Internal Server Error", { status: 500 });
      }
    }
    
  2. app/routes/_index.tsxを下記のように修正

    app/routes/_index.tsx
    import type { MetaFunction } from "@remix-run/cloudflare";
    import { useNavigate, useLoaderData } from "@remix-run/react";
    import { useState } from "react";
    import { loader } from "./task-category-masters-loader";
    export { loader };
    
    export const meta: MetaFunction = () => {
      return [
        { title: "Top" },
        {
          name: "description",
          content: "Top",
        },
      ];
    };
    
    export default function Index() {
      const navigate = useNavigate();
      const [isDeleted, setIsDeleted] = useState(false);
      const [isComplete, setIsComplete] = useState(false);
      const [taskCategoryMasterId, setTaskCategoryMasterId] = useState(""); // 初期値を空文字列として定義
    
      const handleSearchClick = () => {
        const queryParams = new URLSearchParams();
        if (isDeleted) {
          queryParams.append("isDeleted", isDeleted.toString());
        }
        if (isComplete) {
          queryParams.append("isComplete", isComplete.toString());
        }
        if (taskCategoryMasterId !== "") {
          queryParams.append("taskCategoryMasterId", taskCategoryMasterId.toString());
        }
        navigate(`/tasks?${queryParams.toString()}`); // クエリパラメーターを含めて遷移
      };
    
      interface TaskCategoryMaster {
      id: string;
      name: string;
    }
    
      const taskCategoryMasters = useLoaderData<TaskCategoryMaster[]>();
    
      return (
        <div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.8" }}>
          <div>
            <h2>タスク管理</h2>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isDeleted}
                  onChange={(e) => setIsDeleted(e.target.checked)}
                />
                削除済みを表示
              </label>
            </div>
            <div>
              <label>
                <input
                  type="checkbox"
                  checked={isComplete}
                  onChange={(e) => setIsComplete(e.target.checked)}
                />
                完了済みを表示
              </label>
            </div>
            <div>
              <label>
                タスクカテゴリ:
                <select
                  onChange={(e) => setTaskCategoryMasterId(e.target.value)}
                  defaultValue=""
                >
                  <option value="" disabled>選択してください</option>
                  {taskCategoryMasters.map((taskCategoryMaster) => (
                    <option key={taskCategoryMaster.id} value={taskCategoryMaster.id}>
                      {taskCategoryMaster.name}
                    </option>
                  ))}
                </select>
              </label>
            </div>
            <button onClick={handleSearchClick}>検索する</button>
          </div>
        </div>
      );
    }
    
  3. 下記のようにプルダウンのnameの値がtask_category_mastersのnameの値で設定されていることを確認

    CleanShot 2024-06-17 at 22.04.41.gif

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0