TO DO LIST _ 노마드코더 _ 바닐라JS크롬앱만들기

라용·2022년 8월 9일
1

노마드코더 바닐라 JS로 크롬 앱 만들기 강의를 듣고 정리한 기록입니다. 아래 내용은 7.0 - 7.8 에 해당합니다.

1. 기본적인 html을 작성합니다.

할 일을 적어줄 input 태그는 form 안에 넣고, 할 일 목록을 담아줄 ul 태그를 만듭니다. ul 태그 안의 li 태그는 이후 js 로 만들어서 넣습니다.

<form id="todo-form">
	<input type="text" placeholder="Write a To Do and Press Enter" required /> 
	// reaquired 는 필수라는 것
</form>

<ul id="todo-list"></ul> // 이 안의 li 는 js 로 추가한다.

2. html 요소를 js 에서 선택하고 submit 이벤트에 특정 함수를 실행합니다.

document.getElementById() document.querySelector() 를 사용해 form ul input 태그를 js 파일에서 선택합니다. addEventListener()form 태그의 submit 을 감지하고 함수를 실행합니다.

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

function handleToDoSubmit(event) {
	event.preventDefault(); // 기본 동작을 멈추고
	const newTodo = toDoInput.value; // input 에 입력된 값을 변수에 할당하고
	toDoInput.value = ""; // input 을 비워준다. 위에 변수 값이 0이 되는 것은 아님.
}

toDoForm.addEventListener("submit", handleToDoSubmit); 
// 첫번째 인자, submit 를 확인하고 두번째 인자인 함수를 실행

3. 입력한 toDo 를 화면에 보여주는 함수를 추가합니다.

handleToDoSubmit() 함수에 paintToDo() 함수를 추가하고(입력하면 화면에 보여주는 함수 실행), 해당 함수식을 위에 작성합니다. document.createElement()html 태그를 생성하고 appendChild() 를 사용해 자식요소로 태그를 넣어줄 수 있습니다.

function paintToDo(newTodo) { // 텍스트가 들어갈 매개변수 설정
	const li = document.createElement("li"); // li 태그 생성
	const span = document.createElement("span"); // span 태그 생성
	li.appendChild(span); // li 태그 안에 자식요소로 span 태그 넣기
	span.innerText = newTodo; // span 태그 안에 input 값 넣기
	toDoList.appenChild(li); // ul 태그에 위에서 만든 li 넣어주기
}

//  li 를 만들고 span 을 만들고, li 안에 span 을 자식요소로 넣고, 그 span 안에 텍스트를 넣어준다. 텍스트는 아래 input 에서 받는다.

function handleToDoSubmit(event) {
	event.preventDefault(); 
	const newTodo = toDoInput.value; 
	toDoInput.value = ""; 
	paintToDo(newTodo); // 위 함수로 input 값을 보낸다.
}

4. 화면에 뜬 toDo 를 삭제하는 button 을 추가합니다.

아래와 같이 html 에 태그가 추가되도록 js 코드를 수정합니다.

<li>
	<span>text</span> // 텍스트를 이렇게 넣어주었었고,
	<button>x</button> // 이렇게 버튼이 생성되어야 함 click event 를 기다리는
</li>

기존의 paintToDo 함수에 button 태그를 생성해서 넣어주면,

// 기존 코드
function paintToDo(newTodo) { // 텍스트가 들어갈 매개변수 설정
	const li = document.createElement("li"); // li 태그 생성
	const span = document.createElement("span"); // span 태그 생성
	li.appendChild(span); // li 태그 안에 자식요소로 span 태그 넣기
	span.innerText = newTodo; // span 태그 안에 input 값 넣기
	toDoList.appenChild(li); // ul 태그에 위에서 만든 li 넣어주기
}

// 수정 코드
function paintToDo(newTodo) { 
	const li = document.createElement("li"); 
	const span = document.createElement("span"); 
	span.innerText = newTodo;  // span 먼저 넣어주고
	const button = document.creatElement("button"); // button 태그 생성
	button.innerText = "X"; // 그 아래 버튼 생성하세 넣어주고
    button.addEventListener("click", deleteToDo); // 클릭시 제거 함수 실행
	li.appendChild(span);  // 각각 li 안에 넣어주고
	li.appendChild(button);
	toDoList.appenChild(li);  // li 를 ul 에 넣어준다!
}

이제 수정 코드 위에 deleteToDo() 함수를 만들어 줍니다. target 의 부모요소를 선택하는 parentElement 를 활용합니다.

function deleteToDo(event) { 
	const li = event.target.parentElement;  
  	// 클릭한 button 의 부모 요소인 li 선택
	li.remove(); // li 지우기
}

5. 입력한 값을 배열에 담아서 localStorage 에 저장합니다.

지금까지 코드로 할일을 생성하고 삭제하는 것이 가능하지만 새로고침하면 내용이 사라집니다. 그래서 입력한 데이터를 localStorage 라는 브라우저 저장소에 저장합니다. 우선 빈 배열을 만들어서 입력되는 값을 배열에 넣어줍니다.

//빈 배열을 만들고
const toDos = [];

//값이 입력될 때 그 값을 배열에 넣는다.
function handleToDoSubmit(event) {
	event.preventDefault(); 
	const newTodo = toDoInput.value; 
	toDoInput.value = ""; 
	toDos.push(newTodo); // 입력된 값을 배열에 넣기.
	paintToDo(newTodo);
}

이제 배열 내용을 localStorage 에 넣는 함수를 배열 아래쪽에 추가하고, 해당 함수를 handleToDoSubmit 에서 실행해주면,

function saveToDos() {
	localStorage.setItem("todos", toDos)
    // setItme 이 넣어주는 것, "todos" 는 데이터의 이름, 객체의 key 값과 비슷
}

function handleToDoSubmit(event) {
	event.preventDefault(); 
	const newTodo = toDoInput.value; 
	toDoInput.value = ""; 
	toDos.push(newTodo);  // 아래 실행하기 전에 배열에 값이 들어가 있는 상태
	paintToDo(newTodo); 
	saveToDos(); // 이렇게 실행 코드 넣어준다!, 어레이를 로컬스토리지에 넣는 일
}

그리고 저장되는 데이터를 배열 형태로 만들어 주기 위해 JSON.stringify() 를 사용합니다.

function saveToDos() {
	localStorage.setItem("todos", JSON.stringify(toDos));
}

6. localStorage 에 저장된 값을 불러옵니다.

저장된 값을 불러올 때는 localStorage.getItem() 을 사용하는데, 이때 문자열의 값을 배열로 가져오고 싶다면 JSON.parse() 를 사용합니다.

// 이런 식으로 쓸 수 있습니다.
JSON.parse(localStorage.getItem("todos")) 

반복되는 "todos"를 변수로 묶어주고, 입력된 값이 null 이 아닐 경우 (무언가 입력될 경우) 해당 값을 배열 형태로 가져와 화면에 보여줍니다. 배열을 돌면서 함수를 실행하는 forEach 도 활용합니다.


const TODOS_KEY = "todos" // 로컬스토리지에 저장된 데이터의 키값

const savedToDos = localStorage.getItem(TODOS_KEY);

if (savedToDos !== null) { // null 이 아닐 경우, 값이 입력될 경우
	const parsedToDos = JSON.parse(savedToDos); //해당 변수에 배열 형태로 값 추가
	parsedToDos.forEach(paintToDo); // 배열의 각 아이템들이 돌면서 함수 실행
}

여기까지 하면 const toDos = []; 배열이 항상 비어 있는 것으로 시작하고 newTodo 만 로컬스토리지에 저장하기 때문에 복사본이 저장되지 않습니다. 배열을 변경 가능한 변수로 선언하고 함수를 수정해보면,

let toDos = [];

if (savedToDos !== null) { // 비어있지 않다면,  
	const parsedToDos = JSON.parse(savedToDos); 
	toDos = parsedToDos // 추가한 코드, 기존에 작성된 값을 배열에 추가
	parsedToDos.forEach(paintToDo); 
}

이제 삭제버튼을 누르면 로컬스토리지에서 지워지고, 화면에서도 지워지게 해야 합니다.

7. 입력하는 toDo 에 id 값을 주어 localStorage 에서 선택하고 지웁니다.

우리가 쓰는 데이터베이스는 ToDos 라는 배열이고 로컬스토리지는 배열을 복사해두는 곳입니다. 화면에서는 어떤 html 을 지워야 하는지 알지만 로컬스토리지에서는 알 수 없습니다. 배열 안의 textid 넘버가 있다면 로컬스토리지도 확인할 수 있습니다. 랜덤 숫자는 Date.now() 를 활용해서 줄 수 있습니다.

// 기존 코드
function handleToDoSubmit(event) {
	event.preventDefault(); 
	const newTodo = toDoInput.value; 
	toDoInput.value = ""; 
	toDos.push(newTodo);  // 여기서 텍스트 대신 오브젝트를 푸쉬하고 싶다.
	paintToDo(newTodo); 
	saveToDos(); 
}

// 수정 코드
function handleToDoSubmit(event) {
	event.preventDefault(); 
	const newTodo = toDoInput.value; 
	toDoInput.value = ""; 
	const newTodoObj = { // 객체를 선언하고 할당한다.
		text: newTodo, // 객체 안의 value 로 값을 받고
		id: Date.now(), // id의 value 로 랜덤 번호를 받는다.
	}
	toDos.push(newTodoObj); // 그렇게 받은 객체를 배열에 담는다.   
	paintToDo(newTodoObj); // 객체를 그리는 함수로 전달한다.
	saveToDos(); // 배열로 전달된 객체를 로컬스토리지에 담는다.
}

paintTodo() 함수에도 매개변수로 객체가 들어가니 span 에 텍스트를 넣어주는 코드를 수정해야 하고, 입력되는 값의 id 넘버를 li 에도 부여해야 합니다.

function paintToDo(newTodo) { 
	const li = document.createElement("li"); 
	li.id = newTodo.id; // li 에 입력값에 붙는 Id 숫자 값을 넣어준다.
	const span = document.createElement("span"); 
	span.innerText = newTodo.text; // 객체 안의 key 값으로 호출해야 함
	const button = document.creatElement("button");
	button.innerText = "X";
	button.addEventListener("click", deleteToDo); 
	li.appendChild(span);  
	li.appendChild(button);
	toDoList.appenChild(li); 
}

8. id 값을 배열 메소드인 filter 로 확인하고 해당 요소를 제외합니다.

li.id 값이 문자열이므로 비교를 위해 parseInt() 를 사용해 숫자로 바꾸어 주고, filter 를 사용해 해당 id 를 가진 데이터를 제외하고 배여을 만듭니다.

// 기존 코드
function deleteToDo(event) { 
	const li = event.target.parentElement;  
	li.remove(); 
}

// 수정 코드
function deleteToDo(event) { 
	const li = event.target.parentElement;  
	li.remove(); 
	toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id)); 
    // 입력되는 값의 id 와 li 의 id가 다른 것만 남긴다. 같으면 배열에서 제외한다.
	saveToDos()
  	// 지우고 남은 배열을 로컬스토리지에 담아준다.
}

이렇게 하면 기능은 완성입니다.

9. 전체 html, js 코드입니다.

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="todo-box">
        <h1>My ToDoList</h1>
        <form id="todo-form">
            <input type="text" placeholder="Write To Do" required/>
            <button>add</button>
        </form>
        <ul id="todo-list"></ul>
    </div>
    <script src="app.js"></script>
</body>
</html>

javascript

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

let toDos = [];
const TODOS_KEY = "todos"

function saveToDos() {
    localStorage.setItem(TODOS_KEY, JSON.stringify(toDos));
}

function deleteToDo(event) {
    const li = event.target.parentElement;
    li.remove();
    toDos = toDos.filter((toDo) => toDo.id !== parseInt(li.id));
    saveToDos();
}

function paintToDo(newTodo) {
    const li = document.createElement("li");
    li.id = newTodo.id;
    const span = document.createElement("span");
    span.innerText = newTodo.text;
    const button = document.createElement("button");
    button.innerText = "x";
    button.addEventListener('click', deleteToDo);
    li.appendChild(span);
    li.appendChild(button);
    toDoList.appendChild(li);
}

function handleToDoSubmit(event) {
    event.preventDefault();
    const newTodo = toDoInput.value;
    toDoInput.value = "";
    const newTodoObj = {
        text: newTodo,
        id: Date.now(),
    }
    toDos.push(newTodoObj);
    paintToDo(newTodoObj);
    saveToDos();
}

const savedToDos = localStorage.getItem(TODOS_KEY);

if (savedToDos !== null) { 
	const parsedToDos = JSON.parse(savedToDos); 
    toDos = parsedToDos;
    parsedToDos.forEach(paintToDo);
}

toDoForm.addEventListener("submit", handleToDoSubmit);

그리고 CSS 스타일을 잡아줍니다.

profile
Today I Learned

0개의 댓글