자신에게 친절할 것 :)

Projects

[Momentum_ problem shooting] checkbox 가운데 선 긋기

Tashapark 2024. 3. 30. 17:49
728x90

사실.. 이걸 해낸지 꽤 시간이 지났는데

하루하루 지나다 보니까 이제서야 쓴다. 


"노마드 코더의 크롬앱 강의"에서는 delete 버튼만을 만들었기 때문에, 

해낸 표시를 보면서 뿌듯하고 싶던 나는 기능을 추가하기로 결정. ㅎ

 

앞선 포스팅에도 있듯이

 

1. checked  attribute를 추가하게 만들고 싶었음. 

그렇지만, 실패했고 굳이 그럴 필요 없이 checkbox.checked를 사용하면, 

checked된 상태임을 의미함. 

 

2. gpt와 무한 반복의 시간을 거침. 

체크 박스를 만드는 것은 문제가 아니었지만, LS에 저장되서 새고를 해도 유지되게 하는 것은 별개의 문제였는데, 

이게 시간이 좀 걸렸음. 

 

리스트를 새로 만들고 업데이트 하며 저장하는 기능이 이미 있었기 때문에, 

checkBox.id도 같은 해당 todo.id와 같게 부여해서 합쳐지게 만들었음.

 

3. todo.id를 checkBox.id에 부여하는 게 핵심. 

변경된 체크 박스 상태의 저장을 gpt에 도움을 받아서 todo id에 index를 부여해서 확인할 수 있게 만들어줌. 

결론적으로 LS의 todo 배열에는 checked = true or false가 부여되서 저장됨. 

 

체크박스 id를 todo.id와 같게 부여하는 코드를 나타나는 에러 수정하면서 여러번 고쳤음. 

 

4. 되야 되는 데 안될 때는 코드의 순서를 고민할 것

saveToDos를 위로 올려서 저장된 것을 불러오니깐 LS에 저장되기 시작했음. 

 

5. 제.발 gpt가 코드를 망치기 전에 github에 커밋하시길... 

2-3번 이상 왔다갔다하면,,, 코드가 아예 안 동작을 안함.. 

gpt가 구체화된 질문에는 대답을 잘 해주지만 여러번 오가면,,, 문제가 생김.

특히, refactoring 부탁했는데,, 코드가 아예 안 먹히게 되서.. 그러시지 않길 추천함. 

 

6. gpt를 너무 믿지 마시길

gpt는 newObj 변수에 checked 여부를 계속 넣는 형태의 코드를 짜줬는데,

결국 그게 문제였음. 

같은 코드여도 질문을 반복하면 할 때마다 코드를 다르게 주기도 하니깐

한 번 코드를 보여주면, 

재질문 하시길 추천함. 

이거 맞냐고 다시 한번 검토해달라고. 

 

오타나, 로직을 잘 살피진 못하는 점도 염두해두면 좋을 듯. 

 

++ 투두 리스트가 너무 길어져서 루틴 칸을 따로 만들고 싶었음. 

그냥 LS를 합쳐서 사용하려고 했는데 안되서 검색해보니깐, 무조건 나눠지는 게 좋음. 

유지 보수에도 좋고, 한 코드에 여러 기능 넣으면 부딪혀서 작동을 안함. 

 

그래서 투두와 똑같이 루틴 키를 한 개 더 만들어서 해결 

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

const TODOS_KEY = "todos";
const HIDDEN_CLASS = "hidden";

let toDos = []; // 배열로 만들어주기

function saveToDos() {
  localStorage.setItem(TODOS_KEY, JSON.stringify(toDos)); // ("저장명" --> 변수명 따로 저장하면 ""빼고, 저장 내용) //배열로 넣으려고 string으로 바꿔줌
}

function deleteToDo(event) {
  const li = event.target.parentElement; //console.dir로 찾아야 함.
  li.remove(); //어떤 x를 지울 지 몰라서 부여해주는 것임.
  toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id)); // 누른 것을 지운다는 것은 누른 게 아닌 다른 id를 남기는 것.
  saveToDos(); //지웠으면 반드시 저장할 것.
  if (toDos.length === 0) {
    //여기는 배열이 아니라서 length.. 사용 gpt천재
    toDoList.classList.add(HIDDEN_CLASS);
  }
}

// 페이지가 로드될 때 저장된 todo 리스트를 확인하여 체크박스의 상태를 복원
window.addEventListener("DOMContentLoaded", () => {
  const savedToDos = localStorage.getItem(TODOS_KEY);
  if (savedToDos !== null) {
    toDos = JSON.parse(savedToDos);
    // 각 todo 항목에 대해 체크박스 상태를 확인하여 복원
    toDos.forEach((todo) => {
      const checkbox = document.getElementById(`checkbox-${todo.id}`);
      if (checkbox && todo.checked) {
        checkbox.checked = true;
        const text = checkbox.nextElementSibling;
        text.style.textDecorationLine = "line-through";
      }
    });
  }
});

function checkToDo(event) {
  //체크박스 줄 그어지는 것 만들어주려고
  const checkbox = event.target; //무조건 따로 정의를 해줄 것
  const text = checkbox.nextElementSibling; // 체크박스 다음 요소인 텍스트 가져오기
  if (checkbox.checked) {
    text.style.textDecorationLine = "line-through";
  } else {
    text.style.textDecorationLine = "none";
  }
  // 변경된 체크박스 상태를 로컬 스토리지에 저장
  const todoId = checkbox.parentElement.id; // 부모 요소인 li의 id 가져오기
  const index = toDos.findIndex((todo) => todo.id.toString() === todoId); // 해당 id를 가진 todo의 인덱스 찾기
  if (index !== -1) {
    toDos[index].checked = checkbox.checked; // 해당 todo의 checked 속성 업데이트
    saveToDos(); // 변경된 todo 리스트를 다시 저장
  }
}

function paintToDo(newTodo) {
  toDoList.classList.remove(HIDDEN_CLASS);
  const checkBox = document.createElement("input");
  checkBox.setAttribute("type", "checkbox");
  checkBox.id = `checkbox-${newTodo.id}`;
  checkBox.addEventListener("change", checkToDo);
  const li = document.createElement("li");
  li.id = newTodo.id; //list id랑 같이
  const span = document.createElement("span");
  span.innerText = newTodo.text; //span에 투두 넣기 // object니깐 text 나온다고 표기필요
  const button = document.createElement("button");
  button.innerText = "✖️";
  button.addEventListener("click", deleteToDo);
  li.appendChild(checkBox);
  li.appendChild(span); //li에 span 들어감
  li.appendChild(button); //li에 버튼 넣기
  toDoList.appendChild(li); // todo리스트에 li넣어줌
}

function handleToDoSubmit(event) {
  event.preventDefault();
  const newTodo = toDoInput.value; // input의 현재 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);
  //ls에서 가져온 string을 js object로 변경
  // 대개 각 항목별로 뭘 하기 때문에 객체로 변경하는 게 중요함.
  toDos = parsedToDos; // 새로 추가된 리스트로로 덮혀써지지 않게, let으로 변경
  parsedToDos.forEach(paintToDo); // 배열 각각의 항목에 대해 함수 실행 시킴. 항목 개수만큼 실행
  // foreach는 어떤 아이템을 사용하는 지 모르면 의미 없음.
}

 

// 결과

 

728x90
반응형