- 이전 포스팅에서 지역저장소에 데이터를 저장하여 toDoList를 생성하는 방법까지 알아보았다.
- 오늘은 삭제하는 기능을 구현해보자.
1. 삭제기능
- 아래의 사진처럼, 할일을 작성하면 li태그에 입력값이 하나씩 저장되고 x버튼을 눌러 삭제하는 방식이다.
- 삭제를 위해 x버튼을 눌렀을 때, HTML상에서 어떤 x버튼이 어떤 li태그에 존재하는지 구분할 수 있어야 한다. 어떻게 할 수 있을까?
a) event.target
- event.target은 해당 event가 발생한 엘리먼트를 가리키는 기능이다.
- eventHandler 함수를 작성할 때, 매개변수로 선언되어야지 사용할 수 있다.
[구현내용]
1) x버튼이 눌렸을 때, event.target을 이용하여 어떤 엘리먼트에서 이벤트가 발생했는지 찾은 후, 해당 버튼을 감싸고 있는 부모태그인 li태그를 찾아 삭제한다.
- event.target을 사용하여 해당 이벤트가 발생한 엘리먼트를 찾는다.
- parentNode를 사용하여 해당 버튼을 감싸고 있는 부모태그를 찾는다.
- 찾은 자료를 바탕으로 removeChild()를 사용하여 toDoList에서 해당 엘리먼트를 삭제한다.
2) 삭제를 마친 후, 지역저장소에 저장되어있는 데이터(toDos)의 id값과 비교하여 HTML상에 존재하지 않는 id값을 찾은 후 filter함수를 이용하여 해당 id값을 제외한 나머지 값만을 다시 지역저장소에 저장한다. 여기서, const로 설정되어 있는 toDos를 반드시 let으로 바꿔주어야 한다. (toDos = cleanToDos; 이 부분 때문)
- filter()를 사용하여 지역저장소와 toDos의 id값을 비교한 뒤, 양쪽 모두에 없는 값을 제외한 나머지를 리스트로 생성한다.
- 기존의 지역저장소 데이터를 갖고 있는 리스트(toDos)와 새로운 리스트(filter로 만든 리스트)를 교체한다.
- toDos에 새로운 리스트를 적용하기 위하여 toDos 선언시 사용한 const를 let으로 바꿔준다.
[JS코드]
const toDoForm = document.querySelector(".js-toDoForm");
const toDoInput = toDoForm.querySelector("input");
const toDoList = document.querySelector(".js-toDoList");
const TODOS_LS = "toDos";
let toDos = []; // toDo를 저장할 리스트 생성
// 1번 과정
function deleteToDo(event) { // 매개변수로 event 선언
const btn = event.target; // 어떤 버튼인지 찾아낸 후
const li = btn.parentNode; // 해당 버튼을 감싸고 있는 부모태그(li태그)를 찾는다.
toDoList.removeChild(li); // removeChild(): 특정 엘리먼트의 자식 엘리먼트를 삭제하는 함수
// 아직 완벽하게 지워진 것이 아니다. HTML 상에서만 삭제될 뿐 지역저장소에는 기록이 남아있기때문에
// 새로고침을 하면 지웠던 리스트가 다시 생성된다. 그러므로 로컬 저장소에 있는 정보도 삭제해줘야 한다.
// 2번 과정
const cleanToDos = toDos.filter(function filterFn(toDo) {
// filterFn(): 삭제 버튼을 작동으로 어떤 li태그가 삭제되었는지 확인하기위한 함수
return toDo.id !== parseInt(li.id);
// id를 비교하여 없는 삭제된 id를 찾아 반환한다
// parseInt(): 엘리먼트의 속성값은 string이고 toDo.id는 정수형이므로 문자를 정수로 형변환한다.
});
// filter(): filterFn()에서 반환된 데이터를 toDos 리스트에서 걸러내는 함수
toDos = cleanToDos;
// 초기에 선언할 때, toDos는 const타입으로 값을 변경할 수 없었다.
// 그러나 삭제기능 구현을 위해서 let타입으로 변경한다. (toDos = cleanToDos; 이걸 하기 위해서)
saveToDos();
}
function paintToDo(text) {
const li = document.createElement("li");
const delBtn = document.createElement("button");
const span = document.createElement("span");
const newId = toDos.length + 1;
delBtn.innerText = "❌";
delBtn.addEventListener("click", deleteToDo); // 삭제버튼에 이벤트 리스너 등록
span.innerText = text;
li.appendChild(span);
li.appendChild(delBtn);
toDoList.appendChild(li);
li.id = newId;
const toDoObj = {
text: text,
id: newId,
};
toDos.push(toDoObj);
saveToDos();
}
b) 기능 확인
- 이처럼 지역저장소와 엘리먼트 데이터의 생성과 삭제가 잘 되는 것을 볼 수 있다.
- 여기까지, 기본적인 toDoList가 완성되었다.
2. 전체 코드(주석포함)
const toDoForm = document.querySelector(".js-toDoForm");
const toDoInput = toDoForm.querySelector("input");
const toDoList = document.querySelector(".js-toDoList");
const TODOS_LS = "toDos";
let toDos = []; // toDo를 저장할 리스트 생성
function saveToDos() {
// 저장할 때, object를 string으로 형변환
// JSON.stringify()를 이용하면 object를 string으로 형변환할 수 있다.
localStorage.setItem(TODOS_LS, JSON.stringify(toDos));
}
function deleteToDo(event) {
// 삭제 버튼이 클릭되면 li태그가 지워지는 기능을 구현한다.
// 하지만, 어떤 버튼이 클릭되었는지 알지 못한다. 이를 해결하기 위해 target을 사용한다.
// 또 다른 문제점은 해당 삭제버튼이 들어있는 li태그(부모)를 찾아야 한다는 것이다.
// console.dir(event.target)을 실행하면 해당 이벤트가 실행된 엘리먼트의 속성정보를 볼 수 있다.
// 속성정보 중 parentNode 라는 속성값을 사용하면 부모 엘리먼트를 찾을 수 있다.
const btn = event.target;
const li = btn.parentNode;
toDoList.removeChild(li); // removeChild(): 특정 엘리먼트의 자식 엘리먼트를 삭제하는 함수
// 아직 완벽하게 지워진 것이 아니다. HTML 상에서만 삭제될 뿐 지역저장소에는 기록이 남아있기때문에
// 새로고침을 하면 지웠던 리스트가 다시 생성된다. 그러므로 로컬 저장소에 있는 정보도 삭제해줘야 한다.
const cleanToDos = toDos.filter(function filterFn(toDo) {
// filterFn(): 삭제 버튼을 작동으로 어떤 li태그가 삭제되었는지 확인하기위한 함수
return toDo.id !== parseInt(li.id);
// id를 비교하여 없는 삭제된 id를 찾아 반환한다
// parseInt(): 엘리먼트의 속성값은 string이고 toDo.id는 정수형이므로 문자를 정수로 형변환한다.
});
// filter(): filterFn()에서 반환된 데이터를 toDos 리스트에서 걸러내는 함수
toDos = cleanToDos;
// 초기에 선언할 때, toDos는 const타입으로 값을 변경할 수 없었다.
// 그러나 삭제기능 구현을 위해서 let타입으로 변경한다. (toDos = cleanToDos; 이걸 하기 위해서)
saveToDos();
}
function paintToDo(text) {
const li = document.createElement("li"); // li 생성(엘리먼트를 생성시키는 함수 )
const delBtn = document.createElement("button"); //버튼 생성
const span = document.createElement("span");
const newId = toDos.length + 1;
delBtn.innerText = "❌";
delBtn.addEventListener("click", deleteToDo);
span.innerText = text;
li.appendChild(span); // li 태그 내부에 자식태그를 생성하는 함수
li.appendChild(delBtn);
toDoList.appendChild(li);
li.id = newId; // li태그를 삭제할 때, 어떤 li태그를 삭제할 것인지 구분하기 위해 id속성값을 부여
const toDoObj = {
// toDos 배열안에 넣을 정보를 setup
text: text,
id: newId,
};
toDos.push(toDoObj); // setup된 정보를 배열에 push
saveToDos(); // toDos를 지역저장소에 저장하는 함수를 호출
}
function handleSubmit(event) {
event.preventDefault();
const currentValue = toDoInput.value;
paintToDo(currentValue);
toDoInput.value = "";
}
function loadToDos() {
const loadedToDos = localStorage.getItem(TODOS_LS);
if (loadedToDos !== null) {
const parsedToDos = JSON.parse(loadedToDos);
// 스트링으로 바뀌어 저장되어있는 value를 불러와서 사용해야 하므로
// JSON을 활용하여 string을 다시 object로 형변환 시켜준다.
parsedToDos.forEach(function (toDo) {
// parsedToDos에 들어있는 각 데이터를 toDo라는 매개변수에 넣어서 아래 명령문을 실행힌다.
paintToDo(toDo.text);
});
}
}
function init() {
loadToDos();
toDoForm.addEventListener("submit", handleSubmit);
}
init();
[HTML 코드]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vanilla JS</title>
<link rel="stylesheet" href="index2.css" />
</head>
<body>
<form class="js-toDoForm">
<input type="text" placeholder="Write what you need to do." />
</form>
<ul class="js-toDoList"></ul>
<script src="todo.js"></script>
</body>
</html>
'Front-end > Vanilla JS' 카테고리의 다른 글
JS 근본공부 - JS의 동작원리 (0) | 2020.10.23 |
---|---|
JS 근본공부 - 자바스크립트의 역사 (0) | 2020.10.23 |
Vanilla JS - 지역저장소를 이용해서 toDoList 만들기(1) (0) | 2020.10.12 |
Vanilla JS - 지역 저장소(Local Storage) (0) | 2020.10.10 |
Vanilla JS - 시계 만들기 (0) | 2020.10.10 |
댓글