[JS/노마드코더] 바닐라 JS로 크롬 앱 만들기(6) - ToDoList 만들기

최예린·2022년 10월 14일
0

JavaScript

목록 보기
6/7

투두리스트

✔Setup

index.html

    <form id="todo-form">
        <input type="text" placeholder="Write a To Do and Press Enter" required/>
    </form>
    <ul id="todo-list"></ul>

todo.js

const toDoForm = document.getElementById("todo-form");
const toDoInput = document.querySelector("#todo-form input");
const toDoList = document.getElementById("todo-list");

✔Adding To Dos

ul태그 안에 입력받은 newToDo 문자열을 이용해 li태그 element를 하나씩 만들어서 추가할겁니다.

todo.js

function paintToDo(newToDo) {
    /*
    <li>
        <span></span>
    </li>
    */
    const li = document.createElement("li");
    const span =document.createElement("span");
    span.innerText = newToDo;
 
    li.appendChild(span);
    toDoList.appendChild(li);
}

function handleToDoSubmit(event) {
    event.preventDefault(); // prevent refresh when enter
    const newToDo = toDoInput.value;
    toDoInput.value = "";
    paintToDo(newToDo);
}

toDoForm.addEventListener("submit", handleToDoSubmit);

✔Deleting To Dos

여러개의 버튼들이 같은 이벤트 리스너를 통해 이벤트를 기다리고있습니다.
여러개의 delete 버튼중에 내가 클릭한게 어떤 버튼인지 어떻게 알 수 있을까요.

eventListener는 event는 argument로 전달한다. click이벤트 같은 경우
event.target.parentElement 혹은 parentNode를 console에 찍어보면
내가 클릭한 버튼의 부모를 알 수 있습니다.

function deleteToDo(event) {
    const li = event.target.parentElement;
    li.remove();
    // console.dir(event.target.parentElement); // parentNode or parentElement로 클릭한 것의 부모를 알 수 있다.
}

function paintToDo(newToDo) {
    /*
    <li>
        <span></span>
        <button></button>
    </li>
    */
    const li = document.createElement("li");
    const span =document.createElement("span");
    span.innerText = newToDo;
    const button =document.createElement("button");
    button.innerText = "❌";
    button.addEventListener("click", deleteToDo);

    li.appendChild(span);
    li.appendChild(button);
    toDoList.appendChild(li);
}

✔Saving To Dos

Local Storage에는 배열은 저장할 수 없고 텍스트만 저장할 수 있습니다.

JSON.stringify()
자바스크립트 객체, 배열, 어떤 JS코드간에 string으로 만들어줍니다.

localStorage.setItem("todos1", toDos);
localStorage.setItem("todos2", JSON.stringify(toDos));

JSON.stringify()를 쓰면 배열의 형태처럼 보이는 텍스트로 저장됩니다.
이걸 반대로 돌리는 함수가 JSON.parse() 입니다.

✔Loading To Dos

array.forEach()

배열의 각 항목 하나씩 함수를 처리해줍니다.
event처럼 자바스크립트에서 제공해주는게 있습니다. 바로 지금처리하고있는 item에대한 정보입니다. forEach()안에 넣은 함수에 argument로 전달됩니다.

const toDoForm = document.getElementById("todo-form");
const toDoInput = document.querySelector("#todo-form input");
const toDoList = document.getElementById("todo-list");


const TODOS_KEY = "todos";
const toDos = [];

function saveToDos() {
    localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
}

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

function paintToDo(newToDo) {
    /*
    <li>
        <span></span>
        <button></button>
    </li>
    */
    const li = document.createElement("li");
    const span =document.createElement("span");
    span.innerText = newToDo;
    const button =document.createElement("button");
    button.innerText = "❌";
    button.addEventListener("click", deleteToDo);

    li.appendChild(span);
    li.appendChild(button);
    toDoList.appendChild(li);
}

function handleToDoSubmit(event) {
    event.preventDefault(); // prevent refresh when enter
    const newToDo = toDoInput.value;
    toDoInput.value = "";
    toDos.push(newToDo);
    paintToDo(newToDo);

    saveToDos();
}

toDoForm.addEventListener("submit", handleToDoSubmit);

// 새로고침후 나타남
const savedToDos = localStorage.getItem(TODOS_KEY);
if (savedToDos !== null ) {
    const parsedToDos = JSON.parse(savedToDos);
    parsedToDos.forEach(paintToDo);
}

localStorage에 있는 todos를 불러올 수 있게되었지만, 새로고침하면 이전 todos를 덮어쓰게됩니다. toDos 배열을 ★let★으로 바꾸고 새로고침시 localStorage에 값이 있으면 그걸 불러오게하면됩니다.

✔Deleting To Dos in LocalStorage

html에서는 li를 지우는걸 구현했지만 우리의 DB인 toDos 배열에서는 값이 지워지지않습니다. 그렇기때문에 toDos를 localStorage에 저장/불러오기해서 값을 paint하는 지금의 상황에서는 새로고침시 삭제가 반영이되지않습니다.

이를 해결하기위해서는 어떤걸 클릭해서 삭제했는지 알아야하는데 그걸 text로 구별하면 안됩니다. 배열에 만약 "a"가 두개있다면 어떤것인지 구분할 수 없기때문입니다.
그래서 해결책으로 ["a", "b"] 이런식으로 저장하지않고 [{id: ,text: }, ] 이렇게 id를 부여해서 저장해야합니다.

id는 랜덤으로 부여하는데 그때 자주 사용하는 것이 Date.now()입니다. 중복없이 랜덤한 숫자를 만들수있습니다.

html에 각 개체의 id를 넣어줍니다.

array.filter()

[1, 2, 3, 4].filter(sexyFilter)
array에서 item을 삭제할때는 실제로 거기에서 삭제하는게 아니라
지우고싶은 item을 빼고 새로운 array를 만듭니다. 그때 사용하는 것이 filter입니다. 함수에서 true가 반환되면 그때 item이었던 것은 새 array에 포함되고 false가 반환되면 그 item은 새 array에 포함되지않습니다.

function deleteToDo(event) {
    const li = event.target.parentElement; // clicked html element's parent
    li.remove();
    toDos = toDos.filter(item => item.id !== parseInt(li.id)); // toDos - clicked
    saveToDos();
}

전체 소스코드

todo.js

const toDoForm = document.getElementById("todo-form");
const toDoInput = document.querySelector("#todo-form input");
const toDoList = document.getElementById("todo-list");


const TODOS_KEY = "todos";
let toDos = [];

function saveToDos() {
    localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
}

function deleteToDo(event) {
    const li = event.target.parentElement; // clicked html element's parent
    li.remove();
    toDos = toDos.filter(item => item.id !== parseInt(li.id)); // toDos - clicked
    saveToDos();
}

function paintToDo(newToDoObj) {
    /*
    <li>
        <span></span>
        <button></button>
    </li>
    */
    const li = document.createElement("li");
    li.id = newToDoObj.id; // html element에 id 부여하기
    const span =document.createElement("span");
    span.innerText = newToDoObj.text;
    const button =document.createElement("button");
    button.innerText = "❌";
    button.addEventListener("click", deleteToDo);

    li.appendChild(span);
    li.appendChild(button);
    toDoList.appendChild(li);
}

function handleToDoSubmit(event) {
    event.preventDefault(); // prevent refresh when enter
    const newToDo = toDoInput.value;
    toDoInput.value = "";
    const newToDoObj = {
        text: newToDo,
        id: Date.now(),
    };
    toDos.push(newToDoObj);
    paintToDo(newToDoObj);

    saveToDos();
}

toDoForm.addEventListener("submit", handleToDoSubmit);

// 새로고침후 나타남
const savedToDos = localStorage.getItem(TODOS_KEY);
if (savedToDos !== null ) {
    const parsedToDos = JSON.parse(savedToDos);
    toDos = parsedToDos;
    parsedToDos.forEach(paintToDo);
}
profile
경북대학교 글로벌소프트웨어융합전공/미디어아트연계전공

1개의 댓글

comment-user-thumbnail
2023년 4월 6일

저도 같은 강의를 듣고 작업했는데, 세세하게 정리해주신것을 보고 복습도 한것같네요 잘보고갑니다 ^0^

답글 달기