TODO ๋งŒ๋“ค๊ธฐ

๋ฐ”๋‹๋ผJS๋กœ ํˆฌ๋‘๋ฆฌ์ŠคํŠธ ๋งŒ๋“ค๊ธฐ!
๊ธฐ๋ณธํ‹€์„ HTML๋กœ ์ž‘์„ฑํ•œ๋‹ค.:

<form class="js-toDoForm">
    <input type="text" placeholder="Write a to do!"/>
</form>
<ul class="js-toDoList"></ul>

todo.jsํŒŒ์ผ์„ ๋งŒ๋“ค์–ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ž‘์„ฑํ•ด๋ดค๋‹ค.
๋จผ์ €, ํ•„์š”ํ•œ ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜๊ณ ,:

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


const TODOS_LS = 'toDOs';

init(),loadToDos()๋“ฑ ๊ฐ๊ฐ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด๋ณด์ž.:

function loadToDos(){
    const loadedToDos = localStorage.getItem(TODOS_LS);
    if(loadedToDos !== null){

    }
}

function paintToDo(todo){

}

function handleSubmit(event){
    event.preventDefault();
    const currentValue = toDoInput.value;
    paintToDo(currentValue);
    toDoInput.value = "";
}

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

init();

paintToDo์—์„œ ํ•ด์•ผ ํ•  ๊ฒƒ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ TODO๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ์„์ง€๋ฅผ ์ƒ๊ฐํ•˜๊ณ  ์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

<li>๊ฐ€ ์žˆ๊ณ , ์ˆซ์ž ํƒ€์ž… id๋ฅผ ๊ฐ–๊ณ  ์žˆ๋‹ค.

<ul class="js-toDoList">
    <li id="1">
</ul>

์˜ˆ๋ฅผ ๋“ค๋ฉด

<li id="1">์ˆจ์‰ฌ๊ธฐ</li>

๊ทธ๋Ÿผ TODO ๋ฆฌ์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž.
๊ทธ๋™์•ˆ querySelector๋ฅผ ์ด์šฉํ•ด ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์žก์•˜๋‹ค.
๋งŒ์•ฝ ์—˜๋ฆฌ๋จผํŠธ๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด?
document.createElement๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

function paintToDo(text){
    const li = document.createElement("li"),
        delBtn = document.createElement("button"),
        span = document.createElement("span");
    delBtn.innerText = "โŒ";
    span.innerText = text;
    li.appendChild(span);
    li.appendChild(delBtn);
    toDoList.appendChild(li);
}

image.png

<ul>์— <li>๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด์„œ ํ™”๋ฉด์— ์ถœ๋ ฅ๋œ๋‹ค!

TODO ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•˜๊ธฐ

ํ•ด์•ผ ํ• ์ผ์„ ํ•˜๋‚˜๋งŒ ์ €์žฅํ•˜๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์—ฌ๋Ÿฌ๊ฐœ๊ฐ€ ๋ชจ์ธ ๋ชฉ๋ก์„ ์ €์žฅํ•ด์•ผ ํ•˜๋‹ˆ๊น, ํƒ€์ž…์€ array๊ฐ€ ์ ์ ˆํ•˜๊ฒ ๊ตฐ.
๊ทธ๋Ÿฌ๋ฏ€๋กœ toDos๋ฅผ ๋ฐฐ์—ด๋กœ ์ดˆ๊ธฐํ™”๋Š” ์ž‘์—…์„ ํ•ด๋‘์ž.:

const toDos = [];

๊ทธ๋ฆฌ๊ณ  ํ•ด์•ผํ•  ์ผ์„ ์ƒ์„ฑํ–ˆ์„ ๋•Œ toDos ๋ฐฐ์—ด์— ์ถ”๊ฐ€๋˜๋„๋ก ํ•ด๋ณด์ž.
๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ๋Š” toDoObj๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•จ.:

const toDoObj = {};

๊ทธ๋ฆฌ๊ณ  ์ด toDoObj์—๋Š” text๋ผ๋Š” ํ‚ค์— ์ž…๋ ฅ๋ฐ›์€ text๊ฐ€ value๋กœ ์˜ฌ๊ฑฐ์•ผ.
๊ทธ๋ฆฌ๊ณ  id์— ์ˆœ์„œ๋ฅผ ํ‘œ์‹œํ•ด์•ผํ•˜๋‹ˆ๊นŒ id๊ฐ’๋„ ํ•„์š”ํ•˜๊ฒ ์ง€?:

const toDoObj = {
    text: text,
    id: toDos.length + 1
};

๊ทธ๋ฆฌ๊ณ ๋‚˜์„œ toDos๋ฐฐ์—ด์— toDoObj์˜ ๊ฐ์ฒด๋“ค์„ ์ง‘์–ด๋„ฃ์ž.:

toDos.push(toDoObj);

์ž ์‹œ toDoObj์˜ id ๊ฐ’์„ ์ •๋ฆฌํ• ๊ฒŒ. :

function paintToDo(text){
    const li = document.createElement("li"),
        delBtn = document.createElement("button"),
        span = document.createElement("span")
        newId = toDos.length + 1;
    delBtn.innerText = "โŒ";
    span.innerText = text;
    li.appendChild(delBtn);
    li.appendChild(span);
    li.id = newId;
    toDoList.appendChild(li);
    const toDoObj = {
        text: text,
        id: newId
    };
    toDos.push(toDoObj);
}

image.png

์ด์ œ id์˜ ๊ฐ’์ด ์ž๋™์ ์œผ๋กœ ํ•˜๋‚˜์”ฉ ๋Š˜์–ด๋‚˜๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿผ ์ด์ œ saveToDos๋ฅผ ๋งŒ๋“ค์–ด ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•ด๋ณด์ž.

function saveToDos(){
    localStorage.setItem(TODOS_LS, toDos);
}

push์ฒ˜๋ฆฌํ•œ ๋ถ€๋ถ„ ๋‹ค์Œ์— saveToDos๋ฅผ ํ˜ธ์ถœ์„ ํ•˜๊ณ , ์ž…๋ ฅํ•ด๋ณด๋ฉด:

image.png

๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
๊ทผ๋ฐ, [object Object] ํƒ€์ž…์œผ๋กœ ์ €์žฅ๋˜๋Š”๋ฐ ์™œ๊ทธ๋Ÿด๊นŒ?

๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋Š” data๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์—†๋‹ค.

๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ data๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์—†๋‹ค.
์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์žˆ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ stringํƒ€์ž…์œผ๋กœ๋งŒ ์ €์žฅํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ, objectํƒ€์ž…์„ stringํƒ€์ž…์œผ๋กœ ๋ณ€ํ™˜์‹œ์ผœ ์ €์žฅํ•ด์•ผํ•œ๋‹ค.
์œ„ ์ž‘์—…์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” JSON.stringify๋ฅผ ์“ฐ๋ฉด๋œ๋‹ค.:

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

ํ™”๋ฉด์œผ๋กœ ํ™•์ธํ•ด๋ณด์ž.

image.png

์ž…๋ ฅํ•œ ํ…์ŠคํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋˜๊ณ ์žˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์•„์ง ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด ๋‚ด์šฉ์ด ๋˜ ์ง€์›Œ์ ธ์š”...

ํ•˜์ง€๋งŒ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—๋Š” toDos์˜ ๋‚ด์šฉ์ด ๋‚จ์•„์žˆ๋‹ค.
์ด๋ฅผ ์ด์šฉํ•˜์—ฌ ์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด ์ง€์›Œ์ง€๋Š” ์ด์Šˆ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด์ž.

์ผ๋‹จ, loadToDos()ํ•จ์ˆ˜์— loadedToDos๊ฐ€ null์ด ์•„๋‹๋•Œ ์ฝ˜์†”๋ช…๋ น์–ด๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ถœ๋ ฅ์‹œ์ผœ๋ณด๋ฉด:

image.png

์ด์ „์— ์ž…๋ ฅํ–ˆ๋˜ ๋‚ด์šฉ์ด ์ฝ˜์†”์— ์ถœ๋ ฅ๋œ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ ์—ฌ๊ธฐ์—” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.
๋ฌธ์ œ๋Š” ๋ถˆ๋Ÿฌ์˜จ ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์ด ๋ฌธ์ž์—ด์ด๋ผ๋Š” ๊ฒƒ์ด๋‹ค.
JSON.parse()์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฌธ์ž์—ด์„ ๊ฐ์ฒด ํƒ€์ž…์„ ๋ณ€ํ™˜์‹œ์ผœ์ฃผ์ž.:

const parsedToDos = JSON.parse(loadedToDos);

parsedToDos๋ฅผ ์ฝ˜์†”์— ์ฐ์–ด๋ณด๋ฉด, ๋ฌธ์ž์—ด์ด ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜๋˜์„œ ์ฝ˜์†”์— ์ถœ๋ ฅ๋œ๋‹ค.

image.png

์ƒˆ๋กœ๊ณ ์นจํ•ด๋„ ์ด์ œ ๋ณด์ด๋„๋ก ํ•ด๋ณด์ž.

๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—์„œ ๋ถˆ๋Ÿฌ์˜จ ๊ฒƒ์„ ํ™”๋ฉด์— ์ถœ๋ ฅ์‹œ์ผœ์„œ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด๋„ ๊ณ„์† ๋ณด์—ฌ์ฃผ์ž.
๊ทธ ์ „์—... ๋ฐฐ์—ด์—๋Š” forEach๋ผ๋Š” ํ•จ์ˆ˜๊ฐ€ ์žˆ๋‹ค.
์ด ํ•จ์ˆ˜๋Š” ๋ฐฐ์—ด์— ๋‹ด๊ฒจ์žˆ๋Š” ๊ฒƒ๋“ค์„ ๊ฐ ํ•œ๊ฐœ์”ฉ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œ์ผœ์ค€๋‹ค.

parsedToDos.forEach(function()){}

๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ง€๊ธˆ ๋งŒ๋“ค ์ด ํ•จ์ˆ˜๋Š” parsedToDos์— ์žˆ๋Š” ๊ฒƒ๋“ค ๊ฐ๊ฐ์— ๋Œ€ํ•ด ์‹คํ–‰์‹œ์ผœ์ค„๊ฑด๋ฐ,
๊ทธ ๊ฐ๊ฐ์„ toDo๋ผ๊ณ  ์ •ํ• ๊ฒƒ์ด๋‹ค.
์ผ๋‹จ์€ toDo์˜ text๋ฅผ ์ฝ˜์†”์— ์ถœ๋ ฅ์‹œ์ผœ๋ณด์ž.:

parsedToDos.forEach(function(toDo){
    console.log(toDo.text);
});

์•„๋ž˜์ฒ˜๋Ÿผ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ ํ•œ๊ฐœ์”ฉ ์ฝ˜์†”์— ์ฐ์–ด์ฃผ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

image.png

๊ทธ๋Ÿผ ์ด์ œ ๋ฐฐ์—ด์— ๋“ค์–ด์žˆ๋Š” ๊ฐ’๋“ค์„ ๊ฐ ํ•œ๋ฒˆ์”ฉ ์ „๋ถ€ paintToDo()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ถœ๋ ฅ๋˜๊ฒŒ ํ•ด๋ณด์ž.:

function loadToDos(){
    const loadedToDos = localStorage.getItem(TODOS_LS);
    if(loadedToDos !== null){
        const parsedToDos = JSON.parse(loadedToDos);
        parsedToDos.forEach(function(toDo){
            paintToDo(toDo);
        });
    }
}

์ด์ œ ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚ ์•„๊ฐ€์ง€ ์•Š๊ณ  ์ถœ๋ ฅ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

image.png

์ง€์šฐ๋Š” ๊ธฐ๋Šฅ ๋งŒ๋“ค์ž

๋จผ์ € ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์—์„œ todoํ•˜๋‚˜๋ฅผ ์ง€์›Œ์•ผํ•˜๊ณ , ์ €์žฅํ•œ๋‹ค.
์‚ญ์ œ๊ธฐ๋Šฅ์˜ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๊ณ ,
delBtn์„ ๋ˆŒ๋ €์„ ๋•Œ ์ด๋ฒคํŠธ๋ฅผ ํ•˜๋‚˜ ๊ฑธ์–ด์ฃผ์ž.:

function deleteToDo(event){}

function paintToDo(text){
...
delBtn.addEventListener('click', deleteToDo);
}

event์—๋Š” target์ด ์žˆ๋‹ค.
์ด target์„ ์ด์šฉํ•ด์„œ ํ˜„์žฌ ํด๋ฆญ๋œ ์š”์†Œ๋ฅผ ์ฒดํฌํ•˜๊ณ 
์šฐ๋ฆฌ๊ฐ€ ์ง€์šฐ๊ณ ์ž ํ•˜๋Š” ์—˜๋ฆฌ๋จผํŠธ ์ •๋ณด๋ฅผ ๋„˜๊ฒจ์ค˜์„œ ์ง€์›Œ์งˆ ๋Œ€์ƒ์„ ์•Œ๋ ค์ฃผ์ž.:

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

filter๋„ array์˜ ํ•จ์ˆ˜์ค‘์— ํ•˜๋‚˜๋‹ค.
๋ฐฐ์—ด์˜ ๋ชจ๋“  ์•„์ดํ…œ์„ ํ†ตํ•ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ , TRUE์ธ ์•„์ดํ…œ๋“ค๋งŒ ๊ฐ€์ง€๊ณ  ์ƒˆ๋กœ์šด ๋ฐฐ์—ด์„ ๋งŒ๋“ ๋‹ค.

์ ์šฉํ•ด๋ณด๋ฉด TODO์˜ ์ฒซ๋ฒˆ์งธ li๊ฐ’์€ 1 ์ด๋‹ค.
๊ทธ๋Ÿผ li.id ๊ฐ’๊ณผ ๊ฐ™์€ toDo.id๊ฐ’์€ ์‚ญ์ œ๋จ๊ณผ ๋™์‹œ์— cleanToDos๋Š” filter์— ์˜ํ•ด li.id์™€ toDo.id ๊ฐ’์ด ๊ฐ™์ง€ ์•Š์€ ๋ฐฐ์—ด์„ ๋ฆฌํ„ด ์‹œ์ผœ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์ด์ œ toDos ๋ฐฐ์—ด์— ์‚ญ์ œ๋œ ๋‚ด์šฉ์ด ๋“ค์–ด์žˆ๋Š” ๋ฐฐ์—ด์ธ cleanToDos๋กœ ๋Œ€์ฒดํ•˜๊ณ  ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅํ•œ๋‹ค.

function deleteToDo(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;
    svaeToDos();
}

image.png