【Vue.js】タスク追加ページのモーダルをつくる

はじめに

タスクを追加するページのモーダルをコンポーネントとして作成します。

タスク追加ページを作成

$ touch app/javascript/pages/task/components/TaskCreateModal.vue
<template>
  <transition name="fade">
    <div id="task-create-modal">
      <div class="modal" @click.self="handleCloseModal">
                            // モーダル以外の部分をクリックした時にモーダルを閉じる
        <div class="modal-dialog">
          <div class="modal-content">
            <div class="modal-body">
              <div class="from-group mb-3">
                <label for="title">タイトル</label>
                <input type="text" class="form-control"
                  id="title" v-model="task.title"> 
                                   //  v-modelを使って入力された内容をそのままtitleに代入
              </div>
              <div class="from-group mb-3">
                <label for="description">説明文</label>
                <textarea class="form-control" id="description"
                          rows="5" v-model="task.description"></textarea>
                                   //  v-modelを使って入力された内容をそのままdescriptionに代入
              </div>
              <div class="d-flex justify-content-between">
                <button type="button" 
                        class="btn btn-success"
                        @click="handleCreateTask">追加</button> 
                <button type="button"
                        class="btn btn-secondary" 
                        @click="handleCloseModal">閉じる</button>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="modal-backdrop show"></div>
    </div>
  </transition>
</template>

<script>
export default {
  name: 'TaskCreateModal',
  data() {  
    return {
      task: {
        title: '',
        description: ''
      }
    }
  },
  methods :{
    handleCloseModal() {   // 閉じるボタンを押した時に親コンポーネントの'close-modal'イベントを発火
      this.$emit('close-modal')
    },

                           // 第二引数で入力されたデータを渡す。
    handleCreateTask() {   // 追加ボタンを押したときに親コンポーネントの'create-task'イベントを発火
      this.$emit('create-task', this.task)
    }
  }
}
</script>

<template>
  <div>
    <div class="d-flex">
      <div class="col-4 bg-light rounded shadow m-3 p-3">
        <div class="h4">TODO</div>
        <div v-for="task in tasks"
             :key="task.id"
             :id="'task-' + task.id"
             @click="handleShowTaskDetailModal(task)"
             class="bg-white border shadow-sm rounded my-2 p-4">
          <span>{{ task.title }}</span>
        </div>
        <button @click="handleShowTaskCreateModal"
                type="button"
                class="btn btn-secondary">
          タスクを追加
        </button>
      </div>
    </div>
    <div class="text-center">
      <router-link to="/" class="btn btn-dark mt-5">戻る</router-link>
    </div>
    <TaskDetailModal v-if="isVisibleTaskDetailModal"
                     :task="taskDetail"
                     @close-modal="handleCloseTaskDetailModal" />
    <TaskCreateModal v-if="isVisibleTaskCreateModal"
                     @close-modal="handleCloseTaskCreateModal"
                     // 子コンポーネントで閉じるボタンを押した時のイベント
                     @create-task="handleCreateTask"/>
                    // 子コンポーネントで追加ボタンを押した時のイベント
  </div>
</template>

<script> import TaskDetailModal from './components/TaskDetailModal' import TaskCreateModal from './components/TaskCreateModal' // 追加ページのコンポーネントをインポート

export default { components: { TaskDetailModal TaskCreateModal }, name: 'TaskIndex', data() { return { tasks: [], taskDetail: {}, isVisibleTaskDetailModal: false, isVisibleTaskCreateModal: false, // デフォルトでは非表示 } }, created() { this.fetchTasks(); }, methods: { fetchTasks() { this.$axios.get('tasks') .then(res => this.tasks = res.data) .catch(err => console.log(err.status)); }, handleCreateTask(task) {
try { this.$axios.post('tasks', task) // axiosを使って/tasksにpostリクエストを送る .then(res => { // ↓ postリクエストが成功した場合に擬似リロード処理を実行 this.$router.go({path: this.$router.currentRoute.path, force: true}) }); this.handleCloseTaskCreateModal(); } catch(error) { // postリクエストが失敗した場合のエラーをコンソールに表示 console.log(error) } }, handleShowTaskDetailModal { this.isVisibleTaskDetailModal = true; this.taskDetail = task; }, handleCloseTaskDetailModal() { this.isVisibleTaskDetailModal = false; this.taskDetail = {}; }, // ↓ 追加ページのモーダルの表示非表示の処理 handleShowTaskCreateModal() { this.isVisibleTaskCreateModal = true; }, handleCloseTaskCreateModal() { this.isVisibleTaskCreateModal = false; } } } </script>

<style scoped> </style>

完成画面

f:id:study-output:20210623102537p:plain

f:id:study-output:20210623102552p:plain