0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Nuxt3】ちょっとしたタスク管理アプリを作ってみる(編集編)

Posted at

サンプルイメージ

前回記事はこちら↓

下記のようなアプリを作ってみたいと思います↓

【操作手順】
一覧画面から編集したいタスクのID列をクリックする。
①一覧画面(進捗が「完了」のタスクの場合)
vue1.png

一覧画面で進捗が完了しているタスクなら、編集画面のチェックボックスはON表示なっている
②編集画面
vue3.png

逆に、一覧画面で進捗が完了しているタスクなら、編集画面のチェックボックスはOFF表示なっている
②編集画面(進捗が「まだ」のタスクの場合)
vue4.png

ディレクトリ構造

前回記事と同じくディレクトリはこちらになります↓

プロジェクト名
├── pages/
│   ├── index.vue
│   └── detail.vue
├── server/
│   └── api/
│       ├── create.ts
│       └── task.ts
└── prisma/
    ├── migrate
    └── schema.prisma

画面側の(detail.vue)のコード

Vueテンプレートの場合、v-modelといった双方向バインディング機能を活用して遷移先のページに値が渡されるようにしています。

pages/detail.vue
<script setup lang="ts">
import {useRoute} from 'vue-router'

// 現在のルート情報を取得
const route = useRoute();

// クエリパラメータからidを取得
const taskId = route.query.id as number; // ここで型アサーションを加える;
const {data:task,error} = await useAsyncData('taskDetail',() => $fetch(`/api/selectTargetItem?id=${taskId}`));
console.log("取得したJSONデータは、" + JSON.stringify(task));

</script>
<template>
    <div>
        <h1>タスクの詳細ページ</h1>
            <!-- データが正常に取得できた場合 -->
        <div v-if="task">
            <form @submit.prevent="editTask" class="bg-gray-100 border border-black-300 max-w-sm mx-auto px-4 py-4">
                <div>
                    <input type="hidden" v-model="task.id"/>
                </div>
                <div class="mb-5">
                    <input type="text" v-model="task.task" 
                        class="bg-gray-50 border border-gray-300 text-lg rounded-sm w-full"/>
                </div>
                <div class="mb-5">
                    <input type="checkbox" 
                        v-model="task.completed" 
                        :checked="task.completed === true"/>
                </div>
                <button type="submit" class="bg-blue-500 text-white font-bold px-4 py-4 rounded-lg">更新する</button>
            </form>
        </div>
        <div class="flex justify-center py-3">
            <a href="/" 
                class="bg-green-500 text-white font-bold px-4 py-4 rounded-lg">
                一覧に戻る
            </a>
        </div> 
    </div>
    
    
</template>

サーバ側のコード

server/api/selectTargetItem.ts
import { PrismaClient } from '@prisma/client'

export default defineEventHandler(async (event) => {
  // クエリパラメータからtaskIdを取得
  const { id } = getQuery(event)

  // idがstring型の場合、数値に変換
  const taskId = parseInt(id as string)

  if (isNaN(taskId)) {
    return { error: '無効なIDです' }
  }

  const prisma = new PrismaClient()

  try {
      // Prismaを使用してtaskIdに対応するデータを取得
      const task = await prisma.task.findUnique({
        where: {
          id: taskId,
        },
      })

      if (!task) {
        return { error: 'データが見つかりません' }
      }

      return task
  } catch (error) {
      return { error: error.message }
  } finally {
      // Prismaのクライアントを切断
      await prisma.$disconnect()  
  }
})

ChatGPTからのアドバイス

画面側のコードに関するアドバイス

エラーの原因は、タグのvalue属性に対する記述方法にあります。

具体的には、以下のコード部分です:

sample.vue
<input type="text" v-model="task" value=${{task.task}}/>

ここで、value=${{task.task}}と記述していますが、Vueのテンプレートでは、{{ }}は文字列挿入のシンタックスであり、value属性に直接使うことは適切ではありません。さらに、v-modelを使って双方向バインディングを行っているため、value属性は不要です。

解決方法
value属性を削除して、v-modelだけを使うようにします。
taskがオブジェクトである場合(task.taskのような構造)、v-modelは文字列や単純な値に直接バインディングされるべきですが、もしtaskがオブジェクトである場合は、適切なプロパティにバインドする必要があります。
修正後のコードは以下のようになります。

修正後のコード:

sample.vue
<script setup lang="ts">
import { useRoute } from 'vue-router'

// 現在のルート情報を取得
const route = useRoute();

// クエリパラメータからidを取得
const taskId = route.query.id as number; // 型アサーション
const { data: task, error } = await useAsyncData('taskDetail', () => $fetch(`/api/selectTargetItem?id=${taskId}`));
console.log("取得したJSONデータは、" + JSON.stringify(task));
</script>

<template>
    <div>
        <h1>タスクの詳細ページ</h1>
        <h2>タスクのID値は、{{ taskId }}</h2>
        <!-- データが正常に取得できた場合 -->
        <div v-if="task">
            <form @submit.prevent="aa">
                <div>
                    <!-- `task.task` にバインディング -->
                    <input type="text" v-model="task.task" />
                </div>
                <div>
                    <!-- 完了状態を表示・変更できるようにする -->
                    <input type="checkbox" v-model="task.completed" :checked="task.completed === true" />
                </div>
            </form>
            <p>タスク名: {{ task.task }}</p>
            <p>完了: {{ task.completed }}</p>
        </div>
    </div>
</template>

変更点:
value=${{task.task}}を削除し、v-model="task.task"を使用しています。
チェックボックスには、v-model="task.completed"を使用して、完了状態を双方向バインディングしています。

サーバ側のアドバイス

Nuxt3でサーバー側のTypeScriptでtaskIdを取得する方法について説明します。まず、Vueコンポーネントで$fetchを使ってAPIを呼び出し、taskIdをクエリパラメータとして渡します。その後、サーバー側でこのtaskIdを取得し、データを処理する方法を示します。

  1. VueコンポーネントからtaskIdを渡す
    まず、クライアントサイド(Vueコンポーネント)からAPIを呼び出す際に、taskIdをクエリパラメータとして渡します。

タスクの詳細ページ

タスクID: {{ taskId }}

<div v-if="task">
  <p>タスク名: {{ task.title }}</p>
  <p>完了: {{ task.completed }}</p>
</div>

<div v-else>
  <p>タスクが見つかりません。</p>
</div>
  1. サーバーサイドでtaskIdを取得する方法
    サーバーサイドでtaskIdを取得するには、APIハンドラー内でgetQueryを使ってクエリパラメータからtaskIdを取り出します。Nuxt3のAPIルートは、server/apiディレクトリ内に定義されます。

以下に、taskIdを取得してPrismaを使用するサンプルコードを示します。

sample.ts
import { PrismaClient } from '@prisma/client'

export default defineEventHandler(async (event) => {
  // クエリパラメータからtaskIdを取得
  const { id } = getQuery(event)

  // idがstring型の場合、数値に変換
  const taskId = parseInt(id as string)

  if (isNaN(taskId)) {
    return { error: '無効なIDです' }
  }

  const prisma = new PrismaClient()

  try {
    // Prismaを使用してtaskIdに対応するデータを取得
    const task = await prisma.task.findUnique({
      where: {
        id: taskId,
      },
    })

    if (!task) {
      return { error: 'データが見つかりません' }
    }

    return task
  } catch (error) {
    return { error: error.message }
  } finally {
    await prisma.$disconnect()  // Prismaのクライアントを切断
  }
})

3. ポイント
getQuery(event):これにより、HTTPリクエストのクエリパラメータを取得できます。この例では、id(taskId)を取得します。
クエリパラメータとして渡されるidは通常string型なので、parseIntでnumber型に変換します。
prisma.task.findUniqueを使って、取得したtaskIdを基にデータベースからタスクデータを取得します。
4. クエリパラメータの取得方法
クエリパラメータは、URLの?以降に渡されるキーと値のペアです。例えば、/api/selectTargetItem?id=123というURLでid=123を渡します。
getQueryはそのidを取得し、TypeScriptで扱えるようにします。
まとめ
クライアントサイドでtaskIdをクエリパラメータとして渡すために、$fetchを使用します。
サーバーサイド(server/api/selectTargetItem.ts)で、getQuery(event)を使ってtaskIdを取得し、その値を数値に変換してPrismaでデータベースを操作します。
この方法で、Nuxt3のサーバーサイドでtaskIdを取得し、データベースから該当するデータを取得することができます。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?