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?

Vueでモーダルコンポーネントの操作1

Posted at

呼び出し側のコード

TaskView.vue
<template>
  <div class="task-view">
    <div class="task-header">
      <h2 class="text-2xl font-bold mb-4">タスク詳細</h2>
      <div class="flex space-x-4">

        <button
          @click="showEditModal = true"
        >
          編集
        </button>

      </div>
    </div>


    <!-- 編集モーダル -->
    <TaskModal
      v-if="showEditModal"
      :show="showEditModal"
      :editing-task="task"
      :categories="categories"
      @submit="handleTaskSubmit"
      @cancel="showEditModal = false"
    />
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { db } from '../firebase_settings/index.js';
import { doc, getDoc, updateDoc, deleteDoc, collection, getDocs } from 'firebase/firestore';
import TaskModal from '../Modals/TaskModal.vue';

const route = useRoute();
const router = useRouter();
const task = ref(null);
const categories = ref([]);
const showEditModal = ref(false);//タスクモーダルの表示の有無のフラグ


// タスクモーダルから emit('submit') が実行されたときに実行する関数
const handleTaskSubmit = async (taskData) => {//taskDataはタスクモーダルからの引数
  try {
    const taskRef = doc(db, 'tasks', task.value.id);
    await updateDoc(taskRef, {
      ...taskData,
      categoryId: taskData.categoryId || taskData.projectId, // 既存のcategoryIdを保持
      updated_at: new Date()
    });
    
    await fetchTask();
    showEditModal.value = false;
  } catch (error) {
    console.error('タスクの更新に失敗しました:', error);
  }
};
</script>

ポイント

「:show="変数名"」はモーダル側に渡す変数
@submit="handleTaskSubmit"」は モーダル側で「emit('submit', taskData);」が実行されたときに実行する関数名
@cancel="showEditModal = false"」は モーダル側で「emit('cancel')」が実行された時に「showEditModal」変数に false を渡してモーダルを非表示にする処理が実行されるという意味

    <!-- 編集モーダル -->
    <TaskModal
      v-if="showEditModal"
      :show="showEditModal"
      :editing-task="task"
      :categories="categories"
      @submit="handleTaskSubmit"
      @cancel="showEditModal = false"
    />

モーダル画面のコード

TaskModal.vue
<template>
  <div v-if="show" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full z-[70]">
    <div class="relative mx-auto p-5 border shadow-lg rounded-md bg-white modal-container">
      <div class="mt-3">
        <h3 class="text-lg font-medium leading-6 text-gray-900 mb-4">
          {{ editingTask ? 'タスクの編集' : '新規タスクの追加' }}
        </h3>
        <form @submit.prevent="handleSubmit">
          <div class="mb-4">
            <label class="block text-gray-700 text-sm font-bold mb-2" for="title">
              タイトル
            </label>
            <input
              id="title"
              v-model="formData.title"
              type="text"
              class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
              required
            />
          </div>

          <div class="mb-4">
            <label class="block text-gray-700 text-sm font-bold mb-2" for="content">
              内容
            </label>
            <textarea
              id="content"
              v-model="formData.content"
              class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
              rows="4"
              required
            ></textarea>
          </div>

          <div class="mb-4">
            <label class="block text-gray-700 text-sm font-bold mb-2" for="category">
              カテゴリ
            </label>
            <select
              id="category"
              v-model="formData.projectId"
              class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
            >
              <option value="">カテゴリを選択</option>
              <option
                v-for="category in categories"
                :key="category.id"
                :value="category.id"
              >
                {{ category.title }}
              </option>
            </select>
          </div>

          <div class="mb-4">
            <label class="block text-gray-700 text-sm font-bold mb-2" for="priority">
              優先度
            </label>
            <select
              id="priority"
              v-model="formData.priority"
              class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
            >
              <option value="0"></option>
              <option value="1"></option>
              <option value="2"></option>
              <option value="3">緊急</option>
            </select>
          </div>

          <div class="flex justify-end space-x-2">
            <button
              type="button"
              @click="$emit('cancel')"
              class="bg-gray-300 hover:bg-gray-400 text-gray-800 font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
            >
              キャンセル
            </button>
            <button
              type="submit"
              class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline"
            >
              {{ editingTask ? '更新' : '追加' }}
            </button>
          </div>
        </form>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue';
import { getFirestore, collection, doc, setDoc } from 'firebase/firestore';
import { v4 as uuidv4 } from 'uuid';

const props = defineProps({
  show: {
    type: Boolean,
    required: true
  },
  editingTask: {
    type: Object,
    default: null
  },
  categories: {
    type: Array,
    required: true,
    default: () => []
  },
  settings: {
    type: Object,
    required: true
  }
});

const emit = defineEmits(['submit', 'cancel']);

const formData = ref({
  title: '',
  content: '',
  projectId: '',
  priority: 0
});

// 編集モードの場合、フォームに既存のデータを設定
watch(() => props.editingTask, (newTask) => {
  if (newTask) {
    formData.value = {
      title: newTask.title,
      content: newTask.content,
      projectId: newTask.projectId,
      priority: newTask.priority
    };
  } else {
    // 新規作成時はフォームをリセットし、デフォルトカテゴリを設定
    formData.value = {
      title: '',
      content: '',
      projectId: props.settings.active_category_id?.categoryId || '',
      priority: 0
    };
  }
}, { immediate: true });

const handleSubmit = async () => {
  try {
    // ドキュメントIDを生成
    const docId = uuidv4();
    
    // Firestoreに直接保存
    const db = getFirestore();
    const taskRef = doc(db, 'tasks', docId);
    
    const taskData = {
      id: docId, // ドキュメントIDをフィールドにも追加
      title: formData.value.title,
      content: formData.value.content,
      projectId: formData.value.projectId,
      priority: parseInt(formData.value.priority),
      type: 'task',
      categoryId: formData.value.projectId,
      created_at: new Date(),
      updated_at: new Date(),
      checked: false // デフォルトで未完了状態
    };
    
    await setDoc(taskRef, taskData);
    
    // 親コンポーネントに通知
    emit('submit', taskData);
  } catch (error) {
    console.error('タスクの保存に失敗しました:', error);
    // エラーハンドリングを追加する場合はここに実装
  }
};
</script> 

ポイント

propsで親のコンポーネントから値を受け取る
emit()関数で親側に通知ができ、引数を渡すこともできる

const props = defineProps({
  show: {
    type: Boolean,
    required: true
  },
  editingTask: {
    type: Object,
    default: null
  },
  categories: {
    type: Array,
    required: true,
    default: () => []
  },
  settings: {
    type: Object,
    required: true
  }
});
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?