프로젝트/딴짓 추적표

[프로젝트] 딴짓추적표 | 4. 드롭박스로 카테고리 만드는 법

paintover23 2023. 8. 20. 15:00
728x90

딴짓을 하게된 계기를 기록하고 대처하는 차원에서 딴짓 원인을 기록하기로 하였다.

사용자는 아래와 같이 3가지 항목중 하나를 드롭박스 옵션에서 골라 선택할 수 있다.

 

  1. 내부계기(딴짓을 하게 된 원인이 나로부터 발생한 경우: 피로감, 스트레스 등)
  2. 외부계기(딴짓을 하게 된 원인이 외부로부터 발생한 경우: 스마트폰 알림, 전화 등)
  3. 잘못된 계획(딴짓을 하게 된 원인이 잘못된 계획으로부터 발생한 경우)

 

[배운점]

1.  콜백함수의 선언과 호출

// createNote.js

// 메모 레이아웃 그리기
export function createNote(noteValue, selectValue) {
  const notesContainer = document.querySelector('.notesContainer');
  // 메모 레이아웃 그리는 내용(...중략)
}

// 생성하기 버튼 이벤트 리스너
const createBtn = document.querySelector('.btn');
createBtn.addEventListener('click', () => {
  createNote('', '내부계기'); // 콜백함수 호출
  updateStorage();
});
  • 콜백함수는 함수내부에서 사용되는 함수이다. 콜백함수 사용 시 어떤 데이터를 받아오는 것인지 헷갈리는 경우가 많았는데, 이번 예제를 통해 그 흐름을 되짚어보고 원리를 파악할 수 있었다.
  • createNote 함수는 사용자가 입력한 메모인 noteValue와 드롭박스 옵션인 selectValue를 인자로 받는 함수이다.
  • 메모 생성하기 버튼을 클릭하면 'createNote 콜백 함수'를 호출하는 이벤트 리스너를 등록하였다.
  • 사용자가 메모와 옵션을 입력하기 전까지는 '빈 문자열'과 '내부계기'옵션이 초기값으로 하여 메모가 생성된다.
  • 이어, 사용자가 내용 입력하는 이벤트가 발생하면 그 내용이 스토리지에 저장(updateStorage)된다.
// storage.js
// 파싱한 데이터를 화면에 그리기
function showNotes() {
  const savedData = parseSavedData();
  console.log('savedData', savedData);
  savedData.notes.forEach((note, index) => {
    createNote(note, savedData.selects[index]);
  });
}
showNotes();

// 로컬스토리지에 저장되는 형식:
// notes: ['하이', '안녕', '메롱'];
// selects: ['외부계기', '내부계기', '잘못된 계획'];
  • savedData.notes.forEach((note, index) => { 여기에서 note, index 값을 받는다.
  • note는 각각의 요소이다 : '하이', '안녕', '메롱', 각 요소의 index는 0, 1, 2
  • showNotes 함수에서 createNote 콜백 함수를 호출하면서 noteValue, selectValue는 각각 note, savedData.selects[index]가 되었다. 드롭박스 옵션의 인덱스는 note의 인덱스와 상응되는 동일한 값을 갖는다.

 

2. 동적으로 생성되는 dropbox 만드는 방법(option의 속성)

// 동적으로 생성되는 드롭박스 만들기
let dropBox = document.createElement('select'); //select 생성
  dropBox.className = 'dropBox';
  
 // option은 드롭다운 버튼 눌렀을 때 열거되는 목록
 const options = ['내부계기', '외부계기', '잘못된 계획'];
  for (let optionChild of options) {
    let option = document.createElement('option');
    option.text = optionChild;
    dropBox.appendChild(option);
  }
  dropBox.value = selectValue;
  • option 요소는 value 속성과 textContent(또는 text) 속성 모두를 가질 수 있다.
  • 그러나 option에 value 속성만 제공하고 text를 제공하지 않으면, 사용자에게 select 드롭다운에서 아무 것도 표시되지 않는다. 따라서 일반적으로는 option에 텍스트 콘텐츠와 value 속성 모두를 제공한다.
  • 만약 value와 text가 다르게 설정되어야 하는 경우: 
let option = document.createElement('option');
option.value = "internal"; // 저장되는 값
option.textContent = "내부계기";// 화면에서 보여지는 값(option 전체가 다 "내부계기"로 설정됨)
dropBox.appendChild(option);

위와 같이 value는 "internal"로 저장되고, 화면에는 "내부계기"라는 텍스트가 표시된다.

 

3. input 태그와 div 태그의 속성차이

// [예제1] 저장된 노트 로컬스토리지에서 불러오기
function showNotes() {
   notesContainer.innerHTML = localStorage.getItem('allNotes'); //notesContainer는 div
    }
   showNotes();

function updateStorage() {
  localStorage.setItem('allNotes', notesContainer.innerHTML);
 }

// [예제2] input 박스 생성하기
  let inputBox = document.createElement('input'); 
  inputBox.className = 'inputDiv';
  inputBox.value = noteValue; // inputBox는 input
  inputBox.placeholder = '딴짓을 기록하세요.';
  • input 태그와 div 태그는 다르게 작동하기 때문에 저장하는 데이터의 형태나 가져오는 방식에 차이가 발생한다.

 

  • 1. 데이터 저장 방식의 차이:
    • div의 경우 innerHTML 또는 textContent 속성을 사용하여 내용을 가져올 수 있습니다.
    • 반면, input의 경우 value 속성을 사용하여 값을 가져와야 한다.

 

  • 2. Event의 차이:
    • div의 경우 contenteditable가 설정된 상태에서 내용을 편집할 때 input 이벤트keyup 이벤트를 사용할 수 있습니다.
    • 반면, input 태그의 경우 값을 변경할 때 input 이벤트change 이벤트가 발생한다.

 

4. 로컬스토리지에 값을 변환하여 저장하기, 불러오기

[ 로컬스토리지에 저장하기 | object →string 변환: JSON.stringfy(object) ]

- 로컬스토리지는 오브젝트를 저장할 수 없기 때문에 문자열로 바꿔 로컬스토리지에 저장해야 한다.

 

[ 로컬스토리지에서 불러오기 | string object 변환: JSON.parse(localstorage key) ]

- 로컬스토리지에서 값을 불러올 때는 다시 객체 형태로 변환시켜 사용한다.

- 사용하지 않으면 값은 출력되나 타입이 string 이기 때문에 배열 메소드(forEach 등) 사용 시 오류가 발생한다. 

function getSavedData() {
return (
JSON.parse(localStorage.getItem('allNotes')) || {
// allNotes 저장된 값이 있으면 그값을 불러오고, 없으면 [] 빈 값을 반환
notes: [],
selects: [],
}
);
}

 

5. Array.from ( ) 메소드의 사용

export function updateStorage() {
   const notesArray = Array.from(
   notesContainer.querySelectorAll('.inputDiv')
   ).map((input) => input.value);

const selectsArray = Array.from(
notesContainer.querySelectorAll('.dropBox')
).map((select) => select.value);

const savedData = {
notes: notesArray,
selects: selectsArray,
};

saveToLocalStorage(savedData);
}
  1. Array.from의 필요성:
    • Array.from은 문자열과 같은 유사배열객체를 진짜 배열로 바꾸어주는 메소드다. 인자로 유사배열객체와 맵핑함수를 받는다.
    • notesContainer.querySelectorAll('.inputDiv'): notesContainer 내부에서 클래스 이름이 'inputDiv' 인 모든 요소들을 NodeList 형태로 선택한다. NodeList는 배열과 유사하지만, 배열의 메서드들을(예: map, filter, reduce 등) 사용할 수 없는 유사배열객체이다.
    • 배열의 메서드들 을 사용할 수 없기 때문에, Array.from을 사용하여 NodeList를 실제 배열로 변환한다.
  2. map((input) => input.value):
    • 위에서 변환한 배열의 각 요소 (input)에 대해서 .value 속성을 가져와 새로운 배열을 만든다. 결국, 이 배열에는 inputDiv 클래스를 가진 모든 입력 상자의 값들이 저장된다.
728x90
반응형