공부 과정 기록07_노마드코더 시청 후 제작 페이지 코드 설명_todolist 작성(03_04)
이제 마지막으로 todo 리스트 작성 기능까지 구현하면 todo 리스트 페이지가 완성됩니다.
const inputForm = document.getElementById("input-form");
const inputTodo = document.getElementById("inputTodo");
const todoContainer = document.getElementById("todoContainer");
//각각 user의 키값, 정보가 들어갈 변수이다.
let userKey, userObj;
//현재 로그인 되어 있는 객체(status 1)를 찾아 해당 객체의 키값을 반환한다.
function returnUserKey() {
let key, value, i;
for(i = 0; i < localStorage.length; i++) {
key = localStorage.key(i);
value = JSON.parse(localStorage.getItem(key));
if(value.status === 1) {
return key;
}
}
}
//현 상태를 localStorage에 저장하는 역할의 함수
/*
function saveLocal() {
localStorage.setItem(userKey, JSON.stringify(userObj));
}
*/
//삭제 버튼을 눌렀을 때 호출되는 함수
function deleteTodo(event) {
//삭제를 위해 부로 태그(li)의 id 값을 가져왔다.
const parentDiv = event.target.parentNode;
const parentId = parentDiv.id;
//화면상에서의 해당 todo 리스트를 지운다.
parentDiv.remove();
userObj.todo = userObj.todo.filter(obj => (String(obj.id) !== parentId));
localStorage.setItem(userKey, JSON.stringify(userObj));
}
//user 객체를 받아서 화면에 그려주는 역할을 맡는 함수
function paintTodo(userInfo) {
//createElement로 텍스트와 버튼을 감싸줄 li, 텍스트가 들어가는 span, button 태그를 만들어 줬다.
const li = document.createElement("li");
const span = document.createElement("span");
const btn = document.createElement("button");
//추후에 삭제를 위해 li에 id값을 부여하고, span과 button 태그에 각각 맞는 텍스트를 넣어 줬다.
li.id = userInfo.id;
span.innerText = userInfo.text;
btn.innerText = "❌";
//삭제 버튼에 click 이벤트를 추가해 준다.
btn.addEventListener("click", deleteTodo);
//appendChild로 추가해서 화면에 표시되게 한다.
todoContainer.appendChild(li);
li.appendChild(span);
li.appendChild(btn);
}
//input 태그에서 submit 이벤트가 발생할 경우 화면에 입력한 todo 리스트를 표시하기 위한 함수
function handleInputTodo(event) {
//submit의 기본 동작(페이지 새로고침)을 없앤다.
event.preventDefault();
const inputValue = inputTodo.value;
inputTodo.value = "";
//나중에 삭제 버튼 기능 구현 때 사용하기 위해 id를 부여했다.
const userInfo = {
text: inputValue,
id: Date.now()
};
//localStorage에 바뀐 정보를 반영한다.
userObj.todo.push(userInfo);
//새로 todo 리스트가 추가되었을 때 화면에 그려주는 paintTodo 함수로 정보를 넘긴다.
paintTodo(userInfo);
localStorage.setItem(userKey, JSON.stringify(userObj));
}
//화면이 새로 로드되었을 때 해당 계정에 기존 todo 리스트가 있다면 화면에 표시해 줘야 한다.
userKey = returnUserKey();
userObj = JSON.parse(localStorage.getItem(userKey));
//submit 이벤트 발생 시 호출할 함수 추가
inputForm.addEventListener("submit", handleInputTodo);
//현재 로그인된 계정의 todo 속성 길이가 0이 아니라면(그 전에 작성해 놓은 todo 리스트가 있다면),
//반복문을 돌며 paintTodo 함수를 호출하여 화면에 todo 리스트를 그린다.
if(userObj.todo.length !== 0) {
for(let i = 0; i < userObj.todo.length; i++) {
paintTodo(userObj.todo[i]);
}
}
위의 코드가 todo 리스트 저장과 화면에 표시, 삭제하는 기능 전부를 담은 코드입니다.
코드의 순서대로 따라가 보면 todo 리스트를 입력하는 html 요소와 입력된 요소를 표현할 공간인 html 요소값을
가져와 변수에 담았습니다.
그리고 웹 저장소에 있는 유저의 키값과 데이터값이 들어갈 변수를 let으로 선언한 후 함수들 밑에 보면 그 변수에
returnUserKey 함수를 사용하여 키값과 데이터값을 받아옵니다.
returnUserKey 함수를 보면 현재 로그인 되어 있는 유저를 찾아(status가 1인 유저) 그 유저의 키값을 반환하는
기능의 함수로 로그인되어 있는 유저의 todolist 데이터에 입력되는 값을 저장하기 위해 로그인 유저를 찾는
것입니다.
그 이후 input form 태그에서 submit 이벤트가 발생했을 때 handleInputTodo 함수를 호출하게 하는데 사용자가
input 태그 영역에 todo 리스트 값을 입력하고 엔터키를 눌렀을 때 화면에 표시하고 웹 저장소에 저장하기
위함입니다.
그리고 마지막 줄 쪽을 보면 조건문으로 현재 웹 저장소에서 로그인된 유저의 todo 리스트 데이터의 길이가
0이 아닌지 검사하고 있는데, 이 조건문을 넣은 이유는 함수로 넣은 코드가 아닌 일반 영역에 있는 코드들은
페이지가 로드되었을 때 실행되는데 처음 페이지가 로드되었을 때 해당 유저가 전에 작성했었던
todo 리스트들이 있다면 바로 반복문을 돌리며 화면에 todo 리스트를 그려 주는 paintTodo 함수를 호출하게
하기 위함입니다.
이제 기본 코드들은 모두 봤고 이벤트 함수로 처음 호출되는 handleInputTodo 함수부터 보겠습니다.
먼저 매개변수로 받은 event 객체의 preventDefault 함수를 호출하는데 이는 해당 이벤트의 기본 동작을
막아주게 됩니다.
여기서는 submit 이벤트가 발생했을 때 기본 동작으로 페이지가 새로고침되는데 이 새로고침 동작을
막아준다고 생각하면 됩니다.
그리고 사용자가 input 영역에 입력받은 값을 변수에 저장한 후 input 영역에 입력되어 있던 텍스트를
비우고, userInfo라는 객체를 만들어 입력받은 값과 랜덤 id 값을 넣습니다.
(랜덤 id값은 현재 시간을 ms 단위로 나타내는 Date.now 함수를 사용하여 랜덤 id처럼 보이게 했습니다.)
그리고 웹 저장소에서 데이터값으로 받아온 userObj 객체의 todo 배열에 새로 push하게 되고 해당 값을
화면에 그리기 위해 paintTodo 함수를 호출하고 userInfo 객체를 넘겨 줍니다.
그리고 handleInputTodo 함수는 웹 저장소에 변경 사항을 저장하고 끝나게 되는데,
이제 paintTodo 함수를 보겠습니다.
paintTodo 함수에서는 li 태그 안에 텍스트를 넣을 span 태그와 삭제 버튼을 표시할 button 태그를
createElement로 생성하여 값을 넣어주게 되는데 li 태그에 id 값으로 아까 handleInputTodo 함수에서
생성한 랜덤 id값을 지정해 줍니다.
이 id값은 삭제 버튼을 눌렀을 때 활용하게 되고, span 태그와 button 태그에 알맞는 값을 넣은 후
button 태그에는 click 이벤트 함수를 지정합니다.
그리고 처음에 위에서 받아 온 html 요소인 todoContainer 영역에 appendChild로 자식으로 li 태그를
추가해 주게 되면 화면에서도 입력된 값이 표시되게 됩니다.
이제 마지막으로 삭제 버튼을 눌렀을 때 이벤트 함수로써 호출되는 deleteTodo 함수를 보겠습니다.
js에서는 어떤 영역을 클릭하여 이벤트가 발생했을 때 해당 영역에 대한 여러 정보들을 이벤트 함수의
첫 번째 매개변수에 객체로써 전달해 주게 되는데, 그 중에 event.target.parentNode를 사용하면
클릭한 영역의 부모 노드를 가져옵니다.
그럼 button 태그의 부모 노드인 li 태그를 가져오게 되고, 그 태그를 remove 함수를 사용하게 되면
화면에서 삭제되는 것입니다.
하지만 웹 저장소에는 이 일이 반영되지 않는데, 여기서 아까 li 태그에 지정했었던 id 값을 활용하게
됩니다.
웹 저장소에도 해당 todo 리스트가 id 값과 함께 저장되어 있고 그 id값은 li 태그의 id 값과 동일하니
remove로 li 태그를 삭제하기 전 id 값을 받아와 filter 함수를 활용하여 웹 저장소에서의 todo 리스트를
찾아 삭제하고 변경 사항을 저장해 주면 삭제한 상황이 저장소에도 반영됩니다.
이렇게 DB 없이 localStorage라는 브라우저에서 제공하는 웹 저장소를 활용하여 todo 리스트를
구현해 봤습니다.