내가 한 노력들

[ Laravel + Vue.js ] 나만의 To Do List 만들기 - 상세 설정/ 수정하기 본문

IT 공부/Laravel

[ Laravel + Vue.js ] 나만의 To Do List 만들기 - 상세 설정/ 수정하기

JONGI-N CHOI 2021. 8. 30. 23:26

작성한 To Do에 더욱 상세한 설명을 추가하거나, 패턴 / 마감일등을 추가할 수 있는 기능이다. 

 

 

해당 To Do 불러오기

우선 상세설정을 하기 위해서는 이전글에서 만들어둔 Detail 화면에서 상세설정이라는 버튼을 누르면 됩니다. 

 

ToDoDetail.vue

<button type="button" class="btn btn-primary" @click="redirectToDateSet(toDo)">詳細設定</button>

위의 코드가 상세설정 부분의 코드인데, @Click 이벤트로 redirectToDataSet이라는 함수를 실행시킨다. 

 

파라미터로 toDo 데이터를 같이 보내는 것을 확인 가능

 

redirectToDateSet(data) {
            this.$emit('ShowSetDetail', data)
        },

redirectToDataSet함수에서는 $emit을 통해서 ShowSetDetail이라는 함수이름으로 파라미터로 받아온 toDo데이터를 다시 파라미터로 부모 컴포넌트(ToDoList.vue)로 보내는 것을 확인 가능

 

ToDoList.vue

ShowSetDetail(data) {
            this.ToDo = data;
            this.showDetail = true;
        }

$emit을 통해서 받아온 파라미터(toDo 데이터)를 ToDo라는 변수에 담고, showDetail이라는 변수를 true로 변경해줍니다. 

 

showDetail함수는 SetDetail 컴포넌트를 보여주기 위해서 사용될 변수입니다. 

 

 

<template v-if="ToDo === ''">
	//
</template>

<template v-else-if="showDetail">
	<SetDetail :to-do="ToDo" />
</template>

<!-- To Do Detail 화면 -->
<template v-else>
	<ToDoDetail :to-do="ToDo" @show-set-detail="ShowSetDetail"/>
</template>

위를 보면, v-if, v-else-if, v-else를 이용해서 그때 그때 상황에 맞는 컴포넌트가 보이도록 했는데, 

그중에서 v-else-if="showDetail"을 통해서 SetDetail 컴포넌트를 보여주는 것을 확인할 수 있다.

그래서 아까 위의 함수를 봤을 때, 상세설정 버튼이 클릭되면 함수가 실행되어 ShowDetail 변수를 true로 바꿔주기 때문에 해당 SetDetail 컴포넌트가 보여지게 되는 것 입니다. 

 

그리고 파라미터로 받아온 ToDo 데이터를 SetDetail 컴포넌트에 보내주는 것을 확인 가능

 

SetDetail.vue

<script>
export default {
    props: ['toDo'],
    }
</script>

부모 컴포넌트로부터 받아온 toDo 데이터를 사용하기위해 선언을 해주고 

 

<div class="mb-2 border border-2 border-blue-300">
  <input type="text" class="w-full p-2 bg-gray-400" v-model="title">                  
</div>
<div class="mb-2 border border-2 border-blue-300">
  <div>
    <textarea rows="15" placeholder="詳しく書いてください。" v-model="description"
    class="w-full bg-gray-400 p-2"></textarea>                    
  </div>
</div>

위 코드는 title을 수정하는 부분의 text form과 상세내용을 수정할 textarea form에 대한 부분입니다.

 

두개 모두 v-model을 통해서 양방향 바인딩을 하고 있는 것을 볼 수 있습니다.

 

수정할 때에는 기존의 내용을 보여주기 위해서, 받아온 toDo 데이터를 변수에 초기화 해줄 필요가 있습니다

 

data() {               
        return {
          title: this.toDo.title,
          description: this.toDo.description, 
          deadline: this.toDo.deadline,        
        }
    },

data부분에서 받아온 toDo 데이터로 초기화해주면 됩니다. 

 

그러면 자동적으로 기존의 내용들이 화면에 불러와지게 되어 편하게 수정할 수 있게 됩니다. 

 


 

스케줄 설정하기

스케줄 설정은 상세설정에 들어가면 Pattern으로 할지, 마감일로 할지 정할 수 있는 기능

 

Pattern은 매일 해야하는 To Do와 매주 해야하는 To Do로 나뉘어집니다. 

 

마감일은 말그대로 언제까지 해야하는지 날짜를 정할 수 있습니다. 

 

그렇기 때문에 radio 메뉴로 무엇을 선택하느냐에 따라서 다른 Form이 나오게 합니다.

 

<div class="grid grid-cols-2 border border-2 border-blue-300 mb-2 p-2">
            <div>
                <span class="mr-2">Set Schedule</span>
                <span class="mr-4">
                    <input type="radio" name="schedule" value="pattern" v-model="schedule">
                    <label for="huey">Pattern</label> 
                </span>

                <span>
                    <input type="radio" name="schedule" value="deadline" v-model="schedule">
                    <label for="huey">Deadline</label> 
                </span>
            </div>

            <div v-if="schedule === 'pattern'">
                <span class="mr-2">Set Pattern</span>
                <span class="mr-4">
                    <input type="radio" name="pattern" value="daily" v-model="pattern">
                    <label for="huey">毎日</label>
                </span>

                <span>
                    <input type="radio" name="pattern" value="weekly" v-model="pattern">
                    <label for="huey">毎週</label> 
                </span>
                <div v-if="pattern === 'weekly'">
                    <span class="mr-2">Set Day</span>
                    <select class="bg-gray-400 text-white" v-model="day">
                        <template v-for="(day, i) in week" :key="i">
                            <option :value="day">{{ day }}</option>
                        </template>
                    </select>
                </div>
            </div>

            <div v-if="schedule === 'deadline'">
                <label for="date" class="text-sm">Set Deadline</label>                
                <input type="date" id="date" v-model="deadline" class="border border-1 border-dark ml-2 bg-gray-400">
            </div>
        </div>

 

그것을 코드로는 v-if문을 사용하면 쉽게 설정을 할 수 있습니다. 

radio form에는 schedule 변수를 바인딩하여, 선택값에 따라서 deadline이냐 pattern이냐 바뀌도록 합니다. 

 

그럼, 마감일을 정하는 data form은 v-if="schedule === 'deadline'"을 해주면, deadline이 선택됐을 떼 달력 data form이 나오게 됩니다. 

 

 

상세설정 DB에 저장

설정이라는 버튼을 누르게되면 작성한 내용이 DB에 저장이 되게 됩니다. 

 

<button type="button" class="btn btn-warning" @click="submit(toDo.id)">設定</button>

위의 코드가 설정버튼의 코드이고 @Click 이벤트로 submit함수를 실행시킵니다.

 

 

submit(id) {
            if(this.description || this.deadline || this.pattern) {
                if(this.deadline) {
                    const deadline = this.deadline.split('-').map(str => Number(str));
                    const deadlineSec = new Date(deadline[0], deadline[1], deadline[2]).getTime();                    
                    const elapsedMSec = deadlineSec - this.today;
                    this.elapsedDay = elapsedMSec / 1000 / 60 / 60 / 24;                    
                    if(this.elapsedDay < 0) {
                        this.errorMessage = "DeadLineは、過去に設定できません";
                        return;
                    }
                }

                if(this.pattern) {
                    if(this.pattern === 'weekly') {
                        this.setPattern = this.day;
                    } else {
                        this.setPattern = "매일";
                    }
                }
                                
                axios.post('api/todo/updateDetail', {
                    description: this.description,
                    deadline: this.deadline,
                    id: id,
                    pattern: this.setPattern
                }).then(res => {                    
                    console.log(res);
                });
                window.location.href = '/';
            } else {
                this.errorMessage = "詳細内容 or DeadLineを作成してください。"
            }                
        },

submit함수가 긴데, 그 이유가 deadline 설정할 때 현재보다 과거를 설정할 수 없으니까 그것을 검사하는 코드가 추가되서 그렇습니다.

 

그것을 계산하는 방법은 이전 글에서 적은 D-Day 기능에서 썻던 원리와 같습니다. 

 

실질적으로 DB에 저장시키는 코드는 

 

axios.post('api/todo/updateDetail', {
	title: this.title,
    description: this.description,
    deadline: this.deadline,
    id: id,
    pattern: this.setPattern
  }).then(res => {                    
    console.log(res);
  });
  
window.location.href = '/';

값을 수정 또는 저징하기 때문에 axios.post로 api통신을 하게 됩니다.

파라미터로

제목 title

상세내용 description 

마감일 deadline

id 값

패턴 정보 pattern 

를 같이 보냅니다. 

 

api.php

Route::post('/todo/updateDetail', [ToDoListController::class, 'updateDetail']);

 

ToDoListController.php

public function updateDetail() {
        $ToDoList = ToDoList::find(request('id'));
        $ToDoList->title = request('title');
        $ToDoList->description = request('description');
        $ToDoList->deadline = request('deadline');
        $ToDoList->pattern = request('pattern');
        $ToDoList->save();

        $todo_detail = ToDoList::where('id', request('id'))->first();

        return view('welcome');
    }

파라미터로 받은 id값으로 해당 ToDo 데이터를 DB에서 가져오고 

받아온 나머지 정보로 하나씩 수정하여, save합니다. 

 

window.location.href = '/';

그리고 통신이 완료되면, 메인화면으로 redirect를 시켜줍니다. 

 


예외처리 (에러메세지)

 

상황에 맞는 예외처리가 발생하면 해당 에러메세지를 화면에 보여줍니다.

 

 

submit함수에는 if문으로 예외처리를 해주었는데

if(this.description || this.deadline || this.pattern) {
  if(this.deadline) {
    //                  
  if(this.elapsedDay < 0) {
    this.errorMessage = "DeadLineは、過去に設定できません";
    return;
    }
  }

  //
} else {
  	this.errorMessage = "詳細内容 or DeadLineを作成してください。"
}

아무런 내용 변화가 없이 저장을 했을 경우에는 errorMessage에 내용을 적어달라는 메세지를 추가하고

 

마감일을 설정할 때,  현재 날짜보다 과거를 설정하게 되면, 과거는 설정할 수 없다고 에러메세지를 추가 하게 됩니다.

 

<div class="text-gray-500 font-black">
	{{ errorMessage }} 
</div>
data() {      
  return { 
  	errorMessage: '',            
  }
},

에러메세지는 data부분에 ''로 초기화 상태이기 때문에, 예외가 생기기 전까지는 아무런 표시도 하지 않습니다.