목표
선택된 Todo 의 텍스트를 업데이트합니다.
실습
앞서했던 상태 업데이트와 비슷합니다.
li 에 editing 이라는 class 가 추가되면 해당 Todo 에 숨겨져있던 input 이 나옵니다.
우리는 Todo 가 더블클릭 되었을때 이처럼 변하길 원합니다.
먼저 App.vue 에 변화되는 text 와 id 를 받아 텍스트를 업데이트하는 함수를 만들어보겠습니다.
Copy // App.vue
export default {
// ...
methods : {
insertTodo (text) { // ... },
removeTodo (id) { // ... },
updateDone (id) { // ... },
updateTodo ({ id , text }) {
const todos = [ ... this .todos];
const todo = todos .find (todo => todo .id === id);
if (todo) {
todo .text = text;
this .todos = todos;
}
}
}
};
id 와 text 를 받아 해당 todo 를 찾아 text 를 업데이트합니다.
마찬가지로 Todo.vue 에서 사용될 함수이기 때문에 아래와 같이 이벤트를 등록해줍니다.
Copy // App.vue
< template >
< div id = "app" >
< section class = "todoapp" >
< Header @insertTodo="insertTodo" />
< Todo
:todos="todos"
@removeTodo="removeTodo"
@updateDone="updateDone"
@updateTodo="updateTodo"
/>
< Footer />
</ section >
</ div >
</ template >
이제 Todo.vue 로 넘어가겠습니다.
Update 에 대한 모든 정보는 Todo.vue 에서 관리되어집니다. 다른 컴포넌트에서는 Edit 상태에 대한 정보가 전혀 궁금하지 않기 때문입니다.
먼저 Todo.vue 에 edit 데이터를 관리하기 위해 edit state 를 추가합니다.
수정하고 싶은 Todo 가 선택된다면 이 edit state 에 선택된 todo 의 id 와 text 가 채워집니다.
text 를 따로 관리하는 이유는 기존 데이터와 독립되게 만들기 위해서입니다.
수정 취소시 원본 데이터는 손상되면 안되기 때문입니다.
Copy // Todo.vue
< script >
export default {
props: {
todos : { type : Array , default : () => [] }
} ,
data () {
return {
edit : { // edit 데이터를 관리합니다.
text : "" ,
id : - 1
}
};
} ,
methods: {
// ...
}
};
</ script >
이제 더블 클릭 했을때 해당 todo 로 edit 데이터를 채워보겠습니다.
Copy // Todo.vue
< script >
export default {
props: {
todos : { type : Array , default : () => [] }
} ,
data () { // ... },
methods : {
handleRemove (id) { // ... },
handleDone (id) { // ... },
handleEdit ({ text , id }) {
this .edit = {
text ,
id
};
}
}
};
</script>
handleEdit 는 더블 클릭시 선택된 Todo 의 정보를 받아 edit state 를 채우는 함수입니다.
Copy // Todo.vue
< template >
< section class = "main" >
< ul class = "todo-list" >
< li
:class="{todo: true, completed: isDone, editing: edit.id === id }"
v-for = "({ id, text, isDone }) in todos"
:key="id"
>
< div class = "view" >
< input class = "toggle" type = "checkbox" :checked="isDone" @click="handleDone(id)" />
< label @dblclick="handleEdit({ text, id })">{{ text }}</label>
<button class = "destroy" @click="handleRemove(id)"></button>
</div>
<input class = "edit" type = "text" v-model = "edit.text" />
</ li >
</ ul >
</ section >
</ template >
li 에 editing 이라는 class 조건이 추가되었습니다. edit state 에 있는 id 와 해당 todo 의 id 가 같을때만 input 으로 변경됩니다.
label 이 더블클릭 되었을때 해당 handleEdit 함수를 이용하여 edit state 를 업데이트합니다.
input 은 v-model 을 이용하여 edit state 의 text 를 바라봅니다.
여기까지하셨다면 아래와 같이 더블클릭 했을때 input 으로 변경되어지고 선택된 todo 의 내용으로 input 이 채워지게됩니다.
이제 input 에 수정될 값을 입력하고 엔터를 쳤을때 해당 Todo 의 내용이 변경되는 처리만 해주면 됩니다.
input 에 keypress 이벤트를 걸어주고 엔터가 입력될 경우를 캐치하여 edit state 를 App.vue 에서 등록해둔 이벤트를 실행시켜주면 됩니다.
Copy // Todo.vue
< template >
< section class = "main" >
< ul class = "todo-list" >
< li
:class="{todo: true, completed: isDone, editing: edit.id === id }"
v-for = "({ id, text, isDone }) in todos"
:key="id"
>
< div class = "view" >
< input class = "toggle" type = "checkbox" :checked="isDone" @click="handleDone(id)" />
< label @dblclick="handleEdit({ text, id })">{{ text }}</label>
<button class = "destroy" @click="handleRemove(id)"></button>
</div>
<input class = "edit" type = "text" v-model = "edit.text" @keypress="handleUpdate" />
</ li >
</ ul >
</ section >
</ template >
< script >
export default {
props: {
todos : { type : Array , default : () => [] }
} ,
data () { // ... },
methods : {
handleRemove (id) { // ... },
handleDone (id) { // ... },
handleEdit ({ text , id }) { // ... },
handleUpdate ({ keyCode }) {
if (keyCode === 13 ) {
this .$emit ( "updateTodo" , this .edit);
this .edit = { // 추가된 후 edit state 를 리셋합니다
text : "" ,
id : - 1
};
}
}
}
}
</ script >
아래와 같이 수정되는 것을 확인 할 수 있습니다.