자신에게 친절할 것 :)

Web Developing/JS

[JS] to-do list 만들기

Tashapark 2024. 3. 16. 16:35
728x90

// "Normad Coder의 초보자를 위한 바닐라 JS" 들으며, 모멘텀 클론 코딩 중//

처음에는 폼 만들기랑 비슷해서 괜찮을 줄 알았는데

생각보다 너무 복잡하다..

정리하고 한 번 다시 만들어봐야 할 것 같아.

오타 찾느라 시간 낭비도 많이 하고ㅠㅠ

to-do list라는 게 생각보다 기능이 많이 들어간다.

1. todo를 입력하고, 이걸 화면에 나타나게 하고(리스트로), 지우기 버튼도 만들고, 정보를 LS에 저장해야 함.

2. 버튼을 누르면 지워지게 하는데, 각각 화면과 LS 모두에서 지우고 저장되어야 함.

이번에는 따라 하면서, 순서를 확인하면서 해서 그 방법대로 정리해 볼 것.


<HTML>

 <head>
    <meta charset="UTF-8" />
 </head>
 <body>
   <form class="js-todoForm">
      <input type="text" placeholder="write a to do" />
   </form>    
   <ul class="js-toDoList"></ul>
   <script src="JS/todo.js"></script>
 </body>

그냥 무조건 냅다 클래스 만들고 시작할 것.

근데, html에 리스트를 만들어 내는 게 아니라 입력하면 화면에 나타나도록, 하는 것임을 명심할 것.

<JS>

const toDoForm = document.querySelector(".js-todoForm"),
  toDoInput = toDoForm.querySelector("input"),
  toDoList = document.querySelector(".js-toDoList");

const TO_DOOS_LS = "toDos";

let toDos = []; //여러 개라서 목록이 되어야 하기 때문에 처음은 빈 아레이로,헤야 할 일 생성 시 여기에 추가 되도록

function deleteToDo(event) {
  //todo 지우려고 아래 클릭 이벤트 만듬
  const btn = event.target; // 어떤 것인지 모르니깐 target으로 확인함. id확인이 안되서 log말고 dir로 바꿔서 parentNode로 li위치 알아냄.
  const li = btn.parentNode;
  toDoList.removeChild(li); //근데 리프레시하면 그대로임.
  const cleanToDos = toDos.filter(function (toDo) {
    return toDo.id !== parseInt(li.id); //parseInt() 숫자로 바꿔줌
    //모든 todo가 li의 id와 같지 않을 때 나타냄; click해서 사라졌으니까, li에 없는 id가 지우고 싶은 것임.
  }); //깨끗이 지우려고, ;filter는 체크된 아이템을 array로 주는 것. function(toDo)랑 같아서 굳이 안 만들어.
  // foreach처럼 각각의 아이템에 실행될 것
  // 필터가 array를 만들 건데, 함수가 true인 얘들을 return하는 아이템이 있는 걸로
  // todo를 모두 살펴서 id가 1인 것(true)만 가지고 array를 만드는 것
  toDos = cleanToDos; //둘이 달라서 클린은 지울 떄마다 수가 줄어듬.하여간 const를 let으로 바꿔줌
  saveToDos(); //저장하면 리로드 해도 사라짐.
}

function saveToDos() {
  // toDos LS에 저장용.
  localStorage.setItem(TO_DOOS_LS, JSON.stringify(toDos));
} //js는 LS에 data 저장 못함, string 만 저장 가능. 저장되면 무조간 string형태임
// so,  JS object를 string으로 바꿔줘야 함. JSON.stringify()

function paintToDo(text) {
  const li = document.createElement("li"); //quearySelctor는 HTMl에서 가져오지만, 이건 걍 만듦.
  const delBtn = document.createElement("button"); //지우기 버튼 만드는 중. 이모지 되는 거 신기함
  const span = document.createElement("span");
  const newId = toDos.length + 1;
  delBtn.innerText = "❌";
  delBtn.addEventListener("click", deleteToDo); //("event", function)이 들어감
  span.innerText = text;
  li.appendChild(delBtn); // 그니깐 li 안에 span, delBtn 넣겠다.
  li.appendChild(span); // father element 안에 다가 넣는 것. like a chid?
  li.id = newId; // 넣어야 나중에 버튼 클릭 시 어떤 li를 지워야 하는 지 알 수 있음.
  toDoList.appendChild(li); //li를 투두리스트에 넣어서 마무리
  const toDoObj = {
    //이렇게 투두 리스트를 만드는 이유는 LS에 저장을 해야 되서.
    text: text, // key, value가 둘 다 text로 오도록.
    id: newId, // 처음에는 비어있기 때문에 1일 것. 근데 1왜 해줘..? 에쁘게 한다고 변수 만듦 newId
  };
  toDos.push(toDoObj); //toDos array안에 push로 toDoObj를 넣어주는 것
  saveToDos(); //push 뒤에 넣어야 추가된 것을 저장할 수 있음.
}

function handelSubmit(event) {
  event.preventDefault();
  const currentValue = toDoInput.value;
  paintToDo(currentValue);
  toDoInput.value = ""; // 폼에 남은 입력한 글을 지우기 위함. 마치 submit처럼
}

function loadToDos() {
  const loadedToDos = localStorage.getItem(TO_DOOS_LS);
  if (loadedToDos !== null) {
    // !== null이 아니면
    //console.log(loadedToDos); // string으로 나타남.
    const parsedToDos = JSON.parse(loadedToDos); // parse로 다시 object로 바꿔줌
    parsedToDos.forEach(function (toDo) {
      //console.log(toDo.text);// 위에서 toDo가 텍스트여서 텍스트 불러오는 것임.
      paintToDo(toDo.text); //위에 paintToDo function을 다 실행해주는 것.
    });
  }
  // forEach는 함수를 실행하는 데, array에 있는 함수를 한 번씩 실행해 줌.
  //function을 따로 만드는 게 아니라 안에 넣음. 밖으로 빼서 변수 만들어서 넣어도 상관 없음
}

function init() {
  loadToDos();
  toDoForm.addEventListener("submit", handelSubmit);
}

init();

 

.... 해보자.

1. 일단 변수를 만들고 시작하는 것임.

const toDoForm = document.querySelector(".js-todoForm"),

toDoInput = toDoForm.querySelector("input"),

toDoList = document.querySelector(".js-toDoList");

2. 활성화되는 거 따로 빼먹지 않게 바로 만들기 --> 이 방법을 익히자.

function init() {

loadToDos();

[ toDoForm.addEventListener("submit", handelSubmit); ] // 7. 이건 핸들러 만들고 다시 넣음

}

init();

3. 그러면 이제 loadToDos 함수를 만들어야지.

function loadToDos() {

const loadedToDos = localStorage.getItem(TO_DOOS_LS);

[ if (loadedToDos !== null) { --> 13. 이건 뒤에 만듦.

// !== null이 아니면

//console.log(loadedToDos); // string으로 나타남.

const parsedToDos = JSON.parse(loadedToDos); // parse로 다시 object로 바꿔줌

parsedToDos.forEach(function (toDo) {

//console.log(toDo.text);// 위에서 toDo가 텍스트여서 텍스트 불러오는 것임.

paintToDo(toDo.text); //위에 paintToDo function을 다 실행해 주는 것.

}); ]

}

// forEach는 함수를 실행하는 데, array에 있는 함수를 한 번씩 실행해 줌.

//function을 따로 만드는 게 아니라 안에 넣음. 밖으로 빼서 변수 만들어서 넣어도 상관 없음

4. loadedToDos 변수를 만들면 LS 저장할 불러올 변수 다시 만들어야 함.

const TO_DOOS_LS = "toDos";

5. if (loadedToDos !== null) 함수는 일단 나중에 생각.

이건 계속 보이는 거니깐, showing 조건문이 필요 없음.

6. 위에 입력되는 핸들러 함수 만들어야 함.

function handelSubmit(event) {

event.preventDefault(); // 디폴트 값처럼 사라지지 않게 막음

const currentValue = toDoInput.value; // LS에 입력되는 키는 input 값

[ paintToDo(currentValue); ] // 8. 만들고 추가

toDoInput.value = ""; // 폼에 남은 입력한 글을 지우기 위함. 마치 submit처럼

}

7. 핸들러 만들었으면 활성화되게 넣어야지.

[ toDoForm.addEventListener("submit", handelSubmit); ] // 이건 핸들러 만들고 다시 넣음

form에 이벤트 넣어야 되니까 ("event", function)

8. 위에 paintToDo 함수 만들어야 함. css 넣어야 되니깐. 어떻게 리스트 만들어질지 "보이는 것들"

function paintToDo(text) {

const li = document.createElement("li"); //quearySelctor는 HTMl에서 가져오지만, 이건 걍 js에서 만듦.

const delBtn = document.createElement("button"); //지우기 버튼 만드는 중. 이모지 되는 거 신기함

const span = document.createElement("span"); // 공백 넣어주고

[ const newId = toDos.length + 1; ] // 10.

delBtn.innerText = "❌"; // <head>에 포함되어야 함 <meta charset="UTF-8" />

[ delBtn.addEventListener("click", deleteToDo); ] 15.

span.innerText = text;

li.appendChild(delBtn); // 그러니깐 li 안에 span, delBtn 넣겠다.

li.appendChild(span); // father element 안에 다가 넣는 것. like a child?

[ li.id = newId; ] // 10. id 넣어야 나중에 버튼 클릭 시 어떤 li를 지워야 하는 지 알 수 있음. id에 번호가 할당됨.

toDoList.appendChild(li); //li를 투두리스트에 넣어서 마무리

[ const toDoObj = { //10. 이렇게 투두 리스트를 만드는 이유는 LS에 저장을 해야 되서.

text: text, // key, value가 둘 다 text로 오도록.

id: newId, // 처음에는 비어있기 때문에 1일 것. 근데 1왜 해줘..? 예쁘게 한다고 변수 만듦 newId

};

toDos.push(toDoObj); ]//toDos array 안에 push로 toDoObj를 넣어주는 것

[ saveToDos(); ]// 12. push 뒤에 넣어야 추가된 것을 저장할 수 있음!!!

}

9. 실제로 할 일들을 입력하면 array로 저장되게 빈 공간으로 만들어줌.

[ const toDos = []; ]// 17. 나중에 let으로 바뀜

10. 리스트가 LS에 저장되어야 함.

[ const newId = toDos.length + 1; ] // 10. 내 생각엔,, length가 처음에 비어있는 것에.. 뭔가 list가 0으로 할당되지 않기 위함인가?

[ const toDoObj = { //10. 이렇게 투두 리스트를 만드는 이유는 LS에 저장을 해야 되서.

text: text, // key, value가 둘 다 text로 오도록.

id: newId, // 처음에는 비어있기 때문에 1일 것. 근데 1왜 해줘..? 예쁘게 한다고 변수 만듦 newId

};

toDos.push(toDoObj); ]//toDos array 안에 push로 toDoObj(추가된 것)를 넣어주는 것

11. function saveToDos 만들어서 찐 저장해야 함.

function saveToDos() { // toDos LS에 저장용.

localStorage.setItem(TO_DOOS_LS, JSON.stringify(toDos)); // (key, value)

} //js는 LS에 data 저장 못함, string 만 저장 가능. 저장되면 무조건 string 형태라서 JS object를 string으로 바꿔줘야 함. JSON.stringify()

+ JSON --> JavaScript Object Notation : object, string 둘 다로 변경 가능

12. saveToDos 만들었으면 적용해야지

[ saveToDos(); ]// 12. push 뒤에 넣어야 추가된 것을 저장할 수 있음.

13. 이제 아까 넘긴 function loadToDos 마무리.

[ if (loadedToDos !== null) {

// !== null이 아니면 나타나도록, 즉 저장되면 눈에 보이게

//console.log(loadedToDos); // string으로 나타남.

const parsedToDos = JSON.parse(loadedToDos); // parse로 다시 string을 object로 바꿔줌

parsedToDos.forEach(function (toDo) {

//console.log(toDo.text); // 위에서 toDo가 텍스트여서 텍스트 불러오는 것임.

paintToDo(toDo.text); //위에 paintToDo function을 다 실행해 주는 것.

}); ]

}

++ forEach는 함수를 실행하는 데, array에 있는 함수를 한 번씩 실행해 줌. 모든 함수를 실행해 주는 것임.

+ function을 따로 만드는 게 아니라 안에 넣음. 밖으로 빼서 변수 만들어서 넣어도 상관 없음

+ parameter가 매개해 준다는 건 알겠는데 toDo를 따로 정의하지 않아서, 명백히 이해가 되지는 않음.

14. function deleteToDo 만들어야지.

function deleteToDo(event) {

//todo 지우려고 아래 클릭 이벤트 만듦

[ const btn = event.target; // 어떤 것인지 모르니깐 target으로 확인함. id 확인이 안돼서 log 말고 dir로 바꿔서 parentNode로 li 위치 알아냄. 16.

const li = btn.parentNode;

toDoList.removeChild(li); //근데 리프레시 하면 그대로임.

const cleanToDos = toDos.filter(function (toDo) {

return toDo.id !== parseInt(li.id); //parseInt() 숫자로 바꿔줌

//모든 todo가 li의 id와 같지 않을 때 나타냄; click 해서 사라졌으니까, li에 없는 id가 지우고 싶은 것임.

}); //깨끗이 지우려고, ;filter는 체크된 아이템을 array로 주는 것. function(toDo)랑 같아서 굳이 안 만들어.

// foreach처럼 각각의 아이템에 실행될 것

// 필터가 array를 만들 건데, 함수가 true인 얘들을 return 하는 아이템이 있는 걸로

// todo를 모두 살펴서 id가 1인 것(true) 만 가지고 array를 만드는 것 ]

[ toDos = cleanToDos; //둘이 달라서 클린은 지울 때마다 수가 줄어듦. 하여간 const를 let으로 바꿔줌

saveToDos(); ] //저장하면 리로드 해도 사라짐. 18.

}

15. 이벤트를 function paintToDo 아래에 추가. 버튼 누르면 리스트가 화면 상 삭제되도록.

[ delBtn.addEventListener("click", deleteToDo); ] 15.

16. 삭제 더 디테일하게, 어떤 li 할지 타깃 찾고, 새로고침해도 사라지게 LS에서도 깨끗이 지워서 저장까지.

[ const btn = event.target; // 어떤 것인지 모르니깐 target으로 확인함. id 확인이 안 돼서 consol.log 말고 dir로 바꿔 parentNode라는 li 위치 알아냄. 16.

const li = btn.parentNode; // 변수 li 다시 만들어줌

toDoList.removeChild(li); // 화면에서 지워지는 데 새로고침하면 다시 나타남.

const cleanToDos = toDos.filter(function (toDo) { // 아예 clean 하게 만들게 변수 만들기

// filter는 체크된 아이템을 array로 주는 것. function(toDo)랑 같아서 굳이 안 만들어.

// foreach처럼 각각의 아이템에 실행될 것

// 필터가 array를 만들 건데, 함수가 true인 얘들을 return 하는 아이템이 있는 걸로

// 예, todo를 모두 살펴서 id가 1인 것(true) 만 가지고 array를 만드는 것

return toDo.id !== parseInt(li.id); //parseInt() --> 숫자로 바꿔줌; id가 string에 할당돼서 못 찾아서 바꿔 준 것.

}); ]

//모든 todo가 li의 id와 같지 않을 때 나타냄; 즉, click 해서 화면에서 사라진 li에 없는 id를 LS에서 지우고 싶은 것.

17. [ let toDos = []; ]// let으로 바꿔서 toDos랑 cleanToDos를 같게 만들도록 바꿔줌

18. [ toDos = cleanToDos; //둘이 달라서 클린은 지울 때마다 수가 줄어듦. 하여간 const를 let으로 바꿔줌

saveToDos(); ] //저장하면 리로드 해도 사라짐.


휴.. 진짜 힘들었다.

오늘은 여기까지 하고 낼 한 번 더 돌리고 마무리 강의 들어야지..

++ filter랑 forEach 꼭 기억 --> list에 있는 모든 item을 위한 함수를 실행시키는 것.

728x90
반응형