본문 바로가기

웹 개발/JavaScript

JS (5) : To-Do List 만들기 (3)

이 게시물은 Nomadcoders의 JS 무료강의를 참고하여 작성하였다.

바닐라 JS로 크롬 앱 만들기 – 노마드 코더 Nomad Coders

 

바닐라 JS로 크롬 앱 만들기 – 노마드 코더 Nomad Coders

Javascript For Beginners

nomadcoders.co

이전 포스팅까지 우리는 local storage를 사용하여 우리의 To-Do 들을 저장하고 불러오는 기능을 구현하였다. 이번 포스팅에서는 이 To-Do 들을 삭제하는 기능을 구현해 보자.

 

현재, 우리는 삭제 버튼을 눌렀을 때 화면에서는 삭제가 적용된다. 하지만 local storage에서는 적용되지 않는다. 

이제부터 local storage에서 데이터를 삭제하는 기능을 구현해 보자.

 

toDos array 개선

우선, toDos에 저장되어 있는 todo에게 ID를 주도록 하자. ID를 부여하는 이유는, 현재 array에서 삭제할 값을 알기 쉽게 하기 위해서이다.

따라서, 우리는 toDos array를 object 형태로 바꿔줄 것이다.

id는 랜덤한 수로 적용하고, 그에 따른 값은 todo의 text로 적용하도록 하자.

 

JS 코드의 handleToDoSubmit 함수를 다음과 같이 수정해 보자.

 

function handleToDoSubmit(event) {
    event.preventDefault();
    const newTodo = toDoInput.value;
    toDoInput.value = '';
    const newTodoObj = {
        text: newTodo,
        id: Date.now(),
    };
    toDos.push(newTodoObj);
    paintToDo(newTodoObj);
    saveToDos();
}

 

newTodoObj이라는 새로운 객체를 생성하였다. 내부의 값은 text와 id로, text에는 newTodo, id에는 Date.now() 함수를 통해 랜덤한 값을 생성해 주었다. Date.now() 함수는 밀리초를 주는 함수인데, 우리가 보기에 랜덤한 수처럼 보이기 때문에 이 함수를 사용하였다.

 

id를 왜, 어떻게 쓸까?

우리는 이 id값을 사용하기 위해, HTML에 id 값을 표시하려고 한다. 그 이유는 id를 통해 각각의 li item을 구별하고 싶기 때문이다.

HTML에 id값을 표시하기 위해서는 paintToDo 함수에서 newTodo(newTodoObj의 text값) 뿐만 아니라 id도 인자로 전달해 주어야 한다. 

JS 파일에서 handleToDoSubmit 함수와 paintToDo 함수를 다음과 같이 수정해 보자.

 

function paintToDo(newTodoObj) {
    const li = document.createElement('li');
    li.id = newTodoObj.id;
    const span = document.createElement('span');
    const button = document.createElement('button');
    span.innerText = newTodoObj.text;

    button.innerText = 'X';
    button.addEventListener('click', deleteToDo);
    li.appendChild(span);
    li.appendChild(button);
    toDoList.appendChild(li);
}

function handleToDoSubmit(event) {
    event.preventDefault();
    const newTodo = toDoInput.value;
    toDoInput.value = '';
    const newTodoObj = {
        text: newTodo,
        id: Date.now(),
    };
    toDos.push(newTodoObj);
    paintToDo(newTodoObj);
    saveToDos();
}

 

paintToDo 함수에 newTodoObj를 인자로 전달한다.

그 후, 전달받은 인자에서 id와 text를 추출해서 HTML 파일에 id값과 text를 표시한다. li 태그의 id 속성값으로 object의 id값을 적용하고, span 태그 안에 들어가는(화면에 표시되는) 값은 text값으로 적용한다.

 

삭제하기(with filter)

만약 array 에서 뭔가를 삭제할 때, 실제로 그것을 지우는 것은 아니다. 지우고 싶은 item을 빼고 새로운 array를 만드는 것이다.

그렇기 때문에, 기존의 array는 그대로 있고, 새로운 array를 만드는 것이다. 

=> 이때, filter를 사용하면 된다.

filter는 forEach와 사용 방법이 비슷하다. => filter(filter 함수명)

cf) forEach(함수명)는 array 내의 각 item을 괄호 안의 함수의 인자로 전달해서 함수를 실행하는 역할을 한다.

이때, filter 함수의 return값은 boolean 값이다. fliter 함수가 true를 return 하면, 그 item은 새 array에 포함된다. 하지만 filter 함수가 false를 return 하면, 그 item은 새 array에 포함되지 않는다.

 

글로 설명해서 이해가 잘 안 간다면, 우선 코드를 수정한 후 다시 살펴보도록 하자.

JS 파일의 deleteToDo 함수를 다음과 같이 수정해 보자.

 

function deleteToDo(event) {
    const li = event.target.parentElement;
    li.remove();
    toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id));
    saveToDos();
}

 

filter 내부의 filter 함수를 화살표 함수로 작성하였다. 화살표 함수를 이해하기 어렵다면 다음과 같이 코드를 수정해도 문제없이 동작한다. 

 

function deleteToDo(event) {
    const li = event.target.parentElement;

    function deleteFilter(item) {
        return item.id !== parseInt(li.id);
    }

    li.remove();
    toDos = toDos.filter(deleteFilter);
    saveToDos();
}

 

우리가 X 버튼을 눌렀을 때, 누른 li 태그의 id값과 같지 않은 id값을 가지는 object만 새로운 array에 추가하고, 누른 li 태그와 같은 id값을 가지는 object는 새로운 array에서 제외하는 기능을 한다. 

parseInt를 통해 형변환을 하는 이유는, li.id를 통해 가져온 id값이 string이기 때문이다. 현재 item.id로 가져온 id값은 숫자 형태이기 때문에 형변환을 통해 형태를 같게 만들어 준 후 비교를 진행하였다.

 

최종 결과

 

삭제 기능을 구현한 결과는 다음과 같다.

현재 저장된 값을 확인할 수 있다. 저장은 위에서 작성한 코드대로 text, id가 있는 object의 배열 형태로 저장되어 있다. 

 

 

삭제를 진행하면 원하는 값을 삭제하고, 삭제된 내용이 local storage에 적용된다.

 

 

새로고침을 진행하더라도 문제없이 잘 작동하는 것을 확인할 수 있다.

 

이로써, 우리는 간단한 To-Do List 구현을 모두 마쳤다. 추가적으로 수정 기능을 구현하거나, CSS를 적용해 보는 것도 좋은 경험이 될 것이라고 생각한다. 이상으로 To-Do List 관련 포스팅을 마친다.