[Javascript] Day 4

이찬형·2020년 2월 15일

momentumCloneCoding

목록 보기
4/5
post-thumbnail

Day 4


이제 momentum의 메인 기능인 toDoList를 구현해보도록 하겠습니다.

3가지 동작을 줄 거에요.

  • 사용자의 입력을 받는다.
  • 입력 칸 밑에 리스트 형식으로 출력한다.
  • X 버튼을 누르면 리스트에서 지운다.

천천히 가보죠!!

toDoList

먼저 HTML을 만져볼게요.

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Momentum</title>
    <style>
        .form, .greetings {
            display: none;
        }
        
        .showing {
            display: block;
        }
    </style>
</head>
<body>
    <div class="js-clock">
        <span>00:00</span>
    </div>
  
    <form action="" class="js-form form">
        <input type="text" placeholder="What is your name?">
    </form>
    <h4 class="js-greetings greetings">Hello</h4>
    
    <form action="" class="js-toDoForm">
        <input type="text" placeholder="What will you do?">
    </form>
    <ul class="js-toDoList"></ul>
  
    <script src="clock.js"></script>
    <script src="greeting.js"></script>
    <script src="todo.js"></script>
</body>
</html>

하나의 form, input, ul 태그를 만들었어요.

forminputgreeting때와 유사하게 사용자의 입력을 처리하구요,
ul은 리스트를 위해 넣었습니다. 이 밑에 li 태그들이 하나씩 쌓일거에요.

이제todo.js를 작성해봅시다.

우선 작성한 태그들을 객체화해주고, 사용자의 입력을 기다리는 이벤트 리스너와 로컬 스토리지를 처리하는 부분을 만들어봐요.

toDos[]는 리스트의 정보를 저장할 배열입니다. 객체가 들어갈 거에요.

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

const TODOS_LS = "toDo";

let toDos = [];

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

init();

loadToDos()는 로컬 스토리지를 이용하니깐 나중에 만들고, handleToDoSubmit() 먼저 구현하겠습니다.

이 친구는 간단해요. 값을 받아서 출력 및 저장 함수에 던져주면 끝이에요.

function handleToDoSubmit(event) {
  event.preventDefault();
  const currentValue = toDoInput.value;
  printToDoValue(currentValue);
  event.value = "";
}

printToDoValue()로 가봅시다. 여기서 많은 기능을 구현해야 돼요.

우선 ul 태그 밑에 li를 뿌려줘야 하기 때문에 HTML 태그를 생성해야 합니다.
li 태그 안에는 사용자의 입력을 담는 span 태그와 X 버튼인 button 태그가 필요하겠죠?

javascript에서 태그를 만들 땐 createElement()를 사용합니다.
이 친구들을 어떤 태그의 자식으로 만들 땐 appendChild()를 써요.

코드로 먼저 작상해봅시다.
li 태그들에겐 id값을 1, 2, 3.. 이렇게 줄게요.

function printToDoValue(text) {
  const li = document.createElement("li");
  const span = document.createElement("span");
  const button = document.createElement("button");
  span.innerText = text;
  button.innerText = "X";
  li.appendChild(span);
  li.appendChild(button);
  const newId = toDos.length + 1;
  li.id = newId;
  toDoList.appendChild(li);
  const toDoObj = {
    text: text;
    id: newId;
  };
  toDos.push(toDoObj);
  saveToDo();
}

toDos[]toDoObj이란 객체를 넣어줬습니다. 얘는 로컬 스토리지에 담길 친구에요.
나중에 불러오기 쉽도록 배열에 저장했습니다.

이제 로컬 스토리지에 직접 저장하는 saveToDo()를 구현할게요.

function saveToDo() {
  localStorage.setItem(TODOS_LS, JSON.stringfy(toDos));
}

여기서 JSON.stringfy(toDos)를 사용한 이유는 뭘까요??

콘솔로 직접 찍어서 비교해봅시다.

console.log(toDos);
console.log(JSON.stringfy(toDos));

첫 번째 줄이 일반 객체, 두 번째 줄이 JSON 코드가 적용된 객체입니다.

JSON.stringfy는 자바스크립트의 객체를 string으로 바꿔줍니다.

처음에 로컬 스토리지는 문자열을 저장한다고 했죠??
때문에 저장할 때엔 문자열로, 정보를 긁어와서 자바스크립트에서 사용할 땐 객체로 바꿔주는 작업이 필요해요.

두 번째 줄처럼 문자열로 출력되면 잘 저장된 것입니다.

이제 처음으로 돌아가서, init()에서 작성한 loadToDos()을 구현합시다.

forEach문을 쓸 건데, 얘는 배열 하나하나를 다 돌면서 해당 함수를 실행해요.
아래와 같이 작성하면 로컬 스토리지에 있는 배열 요소(객체) 전체가 함수의 인자로 들어갑니다.

function loadToDos() {
  const currentValue = localStorage.getItem(TODOS_LS);
  if (currentValue !== null) {
    const parseToDos = JSON.parse(currentValue);
    parseToDos.forEach(function (todo) {
      printToDoValue(todo.text);
    }
  }
}

지금까지의 결과물이에요.

마지막으로 X 버튼을 누르면 리스트가 사라지는 기능을 구현하겠습니다.
그러기 위해선 먼저 printToDoValue()에 이벤트 리스너를 추가해줘야 해요.

button.addEventListener("click", deleteToDos);

deleteToDos()에선 id값을 기반으로 어떤 리스트의 버튼을 눌렀는지 알아야 합니다.

event.target은 해당 이벤트 발생 시 그 객체를 알려줘요.
위에서 "study JS"를 누르면 그 버튼이 선택되는 것이죠.

우리는 선택된 버튼의 부모 요소인 li의 id값이 필요하잖아요?
target.parent는 타겟의 부모를 알려줘요.

function deleteToDos(event) {
  const btn = event.target;
  const li = btn.parent;
  console.log(btn);
  console.log(li);
}

해당 코드의 결과는 아래와 같아요.

드디어 부모 요소까지 접근이 됐습니다!!
이제 이 친구를 지우고 filter()를 사용해 선택된 값을 제외한 새로운 배열을 만들거에요.

요소를 지울 땐 removeChild()를 쓰면 됩니다.

fliter() 안에 함수를 넣으면, forEach 구문처럼 전체 배열을 돌아서 조건에 맞는 친구들끼리 모아 새로운 배열을 만들어요.

function deleteToDos(event) {
  const btn = event.target;
  const li = btn.parent;
  toDoList.removeChild(li);
  const cleanToDos = toDos.filter(function (todo) {
    return todo.id !== parseInt(li.id);
  });
  toDos = cleanToDos;
  saveTodo();
}

toDos[] 전체를 돌면서 함수를 실행해요.
이 함수는 선택된 li의 id값과 같은 것을 제외한 모든 요소를 cleanToDos 배열에 넣습니다.

parseInt()를 사용한 건 li.id 값이 문자열로 나와서 그런거에요.

이렇게 생성된 배열을 다시 toDos[]에 할당하고 저장합니다.

그러면 완성이에요!!

전체 코드입니다.

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

const TODOS_LS = "toDo";

let toDos = [];

function deleteToDos(event) {
    const btn = event.target;
    const li = btn.parentNode;
    toDoList.removeChild(li)
    const cleanToDos = toDos.filter(function (todo) {
       return todo.id !== parseInt(li.id); 
    });
    toDos = cleanToDos;
    saveToDo();
}

function saveToDo() {
    localStorage.setItem(TODOS_LS, JSON.stringify(toDos));
}

function printToDoValue(text) {
    const li = document.createElement("li");
    const span = document.createElement("span");
    const button = document.createElement("button");
    button.addEventListener("click", deleteToDos);
    const newId = toDos.length + 1;
    span.innerText = text;
    button.innerText = "X";
    li.appendChild(span);
    li.appendChild(button);
    li.id = newId;
    toDoList.appendChild(li);
    const toDoObj = {
        text: text,
        id: newId
    };
    toDos.push(toDoObj);
    saveToDo();
}

function handleToDoSubmit(event) {
    event.preventDefault();
    const currentValue = toDoInput.value;
    printToDoValue(currentValue);
    toDoInput.value = "";
}

function loadToDos() {
    const currentValue = localStorage.getItem(TODOS_LS);
    if (currentValue !== null) {
        const parseToDos = JSON.parse(currentValue);
        parseToDos.forEach(function(todo) {
            printToDoValue(todo.text);
        });
    }
}

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

init();

마무리

정신없습니다 ㅋㅋㅋㅋㅋㅋㅋ 너무 재밌는데 너무 어렵네요.

외우려고 하지 말고 흐름을 봐야하는데 계속 신경쓰이네요..

더 열심히 하겠습니다. 감사합니다 😊

profile
WEB / Security

0개의 댓글