Javascript_30_15

Derek·2021년 1월 2일
0

javascript_30

목록 보기
16/31
post-thumbnail

안녕하세요!

Derek입니다. 😃

벌써.. 반이나 했습니다! 소리질러~하루에 하나씩 한달이면 금방할 줄 알았는데.. 나약한 나레기는 그게 안되네요..

그래도! 30개 다 채울때까지 노력하겠습니다 :)

오늘은 Javascript 30 의 15번째 주제를 가지고 포스팅 해보려고 해요!

Day 15 project는 조금은 난도가 있던 과제였습니다! 시작해볼게요.




15. Localstorage

목표

TodoList 처럼 리스트를 추가하는 기능을 구현한다. 단, 새로고침을 하더라도 정보가 남아있어야한다.

이전에 노마드 코더에서 한번 다뤄본 localStorage 이네요.

<div class="wrapper">
  <h2>LOCAL TAPAS</h2>
  <p></p>
  <ul class="plates">
    <li>Loading Tapas...</li>
  </ul>
  <form class="add-items">
    <input type="text" name="item" placeholder="Item Name" required>
    <input type="submit" value="+ Add Item">
  </form>
</div>

HTML 의 구조는 위와 같습니다! 저희는 ul 안에 리스트형식으로 항목을 넣을거구요.

그럼 기능별로 정리해보겠습니다.


01. 항목 추가 후 LocalStorage 저장 기능

본격적으로 기능 설명을 하기전에, 주의할 점 하나 설명하려고 합니다.

const checkBoxes = document.querySelectorAll("input");
checkBoxes.forEach(input => input.addEventListener("click", () => additems() ));

이런식으로 항목 추가는 되지 않습니다.

왜냐하면, 위 구문은 item 항목이 추가되지 않은 상태에서 실행되므로, 새로 생길 input 들에 대해서 미리 이벤트를 등록하기 어렵기 때문이죠!

그래서, eventDelegation 이 필요합니다. 부모에게 이벤트 위임을 합니다.

const addItems = document.querySelector('.add-items');
const itemsList = document.querySelector('.plates');
const items = JSON.parse(localStorage.getItem("items")) || [];

addItems.addEventListener("submit", addItem);

const addItem = (e) => {
    // if we submit sth by form tag, it automatically refresh. 
    // this would stop that.
    e.preventDefault();

    const text = document.querySelector(".add-items > input").value;
    const item = {
      text: text,
      done: false
    }
    
    items.push(item);
    populateList(items, itemsList);
    localStorage.setItem("items", JSON.stringify(items));
    // this.reset() -> not working.
}

text 변수에 입력한 값을 넣고, 객체화시켜 items 배열에 넣습니다.

items 배열은,

const items = JSON.parse(localStorage.getItem("items")) || [];

이와 같습니다. localStorageitems 항복이 있다면 파싱해서 가져오고, 없다면 빈 배열로 취급합니다.

populateList 함수는,

populateList(items, itemsList);

이런 형식으로 쓰이게 되는데, 이 함수의 내용은 아래와 같아요.

const populateList = (plates = [], plateList) => {
    plateList.innerHTML = plates.map((plate, i) => {
      return `
        <li>
          <input type = "checkbox" data-index = ${i} id = "item${i}" ${plate.done ? "checked": ""}/>
          <label for="item${i}">${plate.text}</label>
        </li>
      `;
    }).join("");
  }

첫 번째 인자로 items 배열을 넣고, 두 번쨰 인자로 이벤트 위임을 준 HTML 상 부모인, plate class의 element를 넘겨줍니다.

생성한 itemsmap 으로 원소 하나하나마다 HTML 요소를 생성하고, 이를 join 으로 쉼표까지 없애줍니다.

return 값도 독특한데요,

<li>
  <input type = "checkbox" data-index = ${i} id = "item${i}" ${plate.done ? "checked": ""}/>
  <label for="item${i}">${plate.text}</label>
</li>

여기서 새롭게 알게된 점은,

  • input 태그와 label 태그는 각각 idfor 값이 같으면 연관성이 생긴다

입니다. MDN 에 따르면이렇다고는 하는데, input 체크박스와 관련있는 label 을 연결시켜주는 것 같습니다 :)

또한, addItem 함수에서 populateList 함수를 통해 화면에서 리스트를 늘려주고, 또 LocalStorage 에 저장작업을 합니다.

localStorage.setItem("items", JSON.stringify(items));

items 배열을 JSON 메소드로 문자열화 시켜 items 라는 keyvalue 로 등록합니다.

02. Toggle 기능 구현

생긴 리스트의 박스를 체크하고, 그 체크 한 내용도 localStorage에 저장하는 기능입니다.

itemsList.addEventListener("click", toggleDone);

const toggleDone = (e) => {
    if(!e.target.matches("input")) return;
    const el = e.target;
    const index = el.dataset.index;

    items[index].done = !items[index].done;

    localStorage.setItem("items", JSON.stringify(items));
    populateList(items, itemsList);
    }

글 초반부에 말씀드린 이벤트 위임관련입니다. 미리 생길 input 들에 대해서 이벤트를 등록하지 못하니, 그 부모에게 이벤트를 위임합니다.

즉, itemsList 에게 니 새로 생길 애기들한테 클릭 이벤트 생기면, 니가 그거 들어라~ 라구요.

그래서 저희가 원하는, 체크박스인지 확인하는 방법은, 첫 번째 줄입니다.

if(!e.target.matches("input")) return;

이렇게 input 이 아니면 return 하게 함으로써 제가 원하는 체크박스만 관리를 할 수 있게 됩니다.

새로 생기는 리스트들은,

<li>
  <input type = "checkbox" data-index = ${i} id = "item${i}" ${plate.done ? "checked": ""}/>
  <label for="item${i}">${plate.text}</label>
</li>

이런 형식이였죠. input 태그에 data-index 가 존재합니다. 이를 이용해 토글을 시켜줘요.

const index = el.dataset.index
items[index].done = !items[index].done;

이렇게 dataset 을 사용해 손쉽게 done 항목을 toggle 시키는 기능까지! 구현이 되었고,

localStorage.setItem("items", JSON.stringify(items));

localStorage 에 세팅하는 것까지 해서, 기능 구현이 완료되었습니다.




오늘은 새로 알게된 사실도 많았고 눈에 보이는 이쁜.. 기능이라 재밌었던것 같아요. 특히 백틱으로 리턴해서 HTML 요소를 추가하는 것은 굉장히 유용할 것 같아요.

틀린내용이나 수정할 내용이 있다면 언제든지 피드백 부탁드립니다!
감사합니다!🤗

profile
Whereof one cannot speak, thereof one must be silent.

0개의 댓글