본문 바로가기

Front-End/JavaScript

[JavaScript]Todo-List 만들기(2)

어느정도 왠만한 todo-list 같아졌다.

 

 

 

 

아래는 js 파일.

index.js

let todoList = [];
let completedList = [];

let num =1;
//returnId는 string 


const todoListElement = document.querySelector(".todo-list");
const completedListElement = document.querySelector(".completed-list");

const initTodoDivElement = document.querySelector(".todo-initDiv");
const initTodoFormElement = document.querySelector(".todo-item");
const initTodoInputElement = document.querySelector("input");
const proposeNewTodoElement = document.querySelector(".todo-item-add");


/*로컬스토리지에 저장하는 함수들*/
const TODOS_KEY = "todos";
function saveToDos() {   //로컬스토리지에 투두를 저장하는 함수
    localStorage.setItem(TODOS_KEY, JSON.stringify(todoList));
  }

const COMPLETEDS_KEY = "completeds";
function saveCompleted() { //로컬스토리지에 완료한 일을 저장하는 함수
    localStorage.setItem(COMPLETEDS_KEY, JSON.stringify(completedList));
}


/*Handle 함수들(eventListener의 함수)*/
function handleToDoInitSubmit(event){ //처음에 할 일을 입력하고 저장했을 때
    event.preventDefault();

    const initTodo = initTodoInputElement.value;
    const initTodoArr = [num,initTodo];
    todoList.push(initTodoArr);
    initTodoDivElement.remove();

    paintTodo(initTodo);
    paintProposeNewTodo();
    saveToDos();
}

function handleButtonModify(event) //수정 버튼을 클릭했을 때
{   const mustDeleteTodoElement = event.target.parentElement;
    const returnId = mustDeleteTodoElement.id;
    const beforeModifyTodo = mustDeleteTodoElement.querySelector("span").innerText;
    mustDeleteTodoElement.remove();

    paintModifyTodo(beforeModifyTodo,returnId);
    SendBackProposeNewTodo();
}

function handleButtonSave(event){ //수정 하고 submit했을 때. //한번 수정한 전적이 있는 투두는 이후 수정을 또 하고 저장해도 이 상태
    event.preventDefault();

    const mustDeleteTodoElement = event.target.parentElement.parentElement;
    const returnId = mustDeleteTodoElement.id;
    const afterModifyTodo = mustDeleteTodoElement.querySelector("input").value;
    mustDeleteTodoElement.remove();

    for (let todo of todoList){
        if (todo[0] === parseInt(returnId)) {
            todo[1] = afterModifyTodo;
        };
    }
    
    saveToDos();
    
    const div = document.createElement("div");
    div.className ="todo-item";
    div.id = returnId;

    const span = document.createElement("span");
    span.className = "todo-readonly";
    span.innerText = afterModifyTodo;

    const buttonModify = document.createElement("button");
    buttonModify.innerText = "✏️";
    buttonModify.addEventListener("click",handleButtonModify);

    const buttonComplete = document.createElement("button");
    buttonComplete.innerText = "✓";
    buttonComplete.addEventListener("click",handleButtonComplete);

    const buttonDelete = document.createElement("button");
    buttonDelete.innerText = "❌";
    buttonDelete.addEventListener("click",handleButtonDeleteReadonly);

    div.appendChild(span);
    div.appendChild(buttonModify);
    div.appendChild(buttonComplete);
    div.appendChild(buttonDelete);
    todoListElement.appendChild(div);

    
    SendBackProposeNewTodo();
}

function handleNewTodoElement() { //"할 일 추가"를 눌렀을 때
    const proposeNewTodoElement = document.querySelector(".todo-item-add");
    proposeNewTodoElement.remove()

    PaintWriteTodo();
}

function handleToDoSubmit(event){ //새로운(not init) 할 일을 추가하고 submit했을 때
    event.preventDefault();

    const mustDeleteTodoElement = event.target.parentElement.parentElement;
    const todo = mustDeleteTodoElement.querySelector("input").value;
    mustDeleteTodoElement.remove();

    const todoArr = [num,todo];
    todoList.push(todoArr);
    saveToDos();

    paintTodo(todo);
    paintProposeNewTodo();
}

function handleButtonComplete(event) { //완료(✓) 버튼을 눌렀을 때
    const mustDeleteTodoElement = event.target.parentElement;
    const returnId = mustDeleteTodoElement.id;
    const completed = mustDeleteTodoElement.querySelector("span").innerText;
    mustDeleteTodoElement.remove();

    todoList = todoList.filter((element) =>element[0] !==parseInt(returnId));
    saveToDos();

    const completedArr = [parseInt(returnId),completed];
    completedList.push(completedArr);
    saveCompleted();
    
    paintCompleted(completed,returnId);  
}

function handleButtonUp(event) { //completed를 다시 todo로 올리는 버튼을 눌렀을 때
    const mustDeleteTodoElement = event.target.parentElement;
    const completed = mustDeleteTodoElement.querySelector("span").innerText;
    const returnId = mustDeleteTodoElement.id;
    mustDeleteTodoElement.remove();

    const todoArr = [parseInt(returnId),completed];
    todoList.push(todoArr);
    saveToDos();

    completedList = completedList.filter((element) =>element[0] !==parseInt(returnId));
    saveCompleted();
    
    paintTodo(completed,returnId);
    SendBackProposeNewTodo();
}

function handleButtonDeleteReadonly(event)  { //form 형식이 아닌 투두들을 지우는데 사용
    const mustDeleteTodoElement = event.target.parentElement;
    const returnId = mustDeleteTodoElement.id;
    mustDeleteTodoElement.remove();

    todoList = todoList.filter((element) =>element[0] !==parseInt(returnId));
    saveToDos();
}

function handleButtonDeleteWhileModify(event) { //form 형식인 투두들을 지우는데 사용
    event.preventDefault();

    const mustDeleteTodoElement = event.target.parentElement.parentElement;
    const returnId = mustDeleteTodoElement.id;
    mustDeleteTodoElement.remove();

    todoList = todoList.filter((element) =>element[0] !==parseInt(returnId));
    saveToDos();
}


/* Paint functions*/
function PaintWriteTodo() { //todo를 새롭게 입력하는 상태 paint
    const div =  document.createElement("div");
    num +=1;
    div.id = num.toString();

    const form = document.createElement("form");
    form.className = "todo-item";

    const input = document.createElement("input");
    input.type = "text";
    input.className = "todo-input";
    input.placeholder= "할 일을 입력하세요";

    const buttonSave = document.createElement("button");
    buttonSave.type = "submit";
    buttonSave.className = "save";
    buttonSave.innerText = "저장";
    buttonSave.addEventListener("click",handleToDoSubmit);

    form.appendChild(input);
    form.appendChild(buttonSave);
    div.appendChild(form);
    todoListElement.appendChild(div);
}

function paintTodo(todo,returnId){ //todo를 입력하고 저장하면 나타나는 상태 paint //수정 전에만 나타남.
    const div = document.createElement("div");
    div.className ="todo-item";

    if (returnId === undefined)
    {
        div.id = num.toString();
    }
    else{   //completed였던 항목이 올라올 때
        div.id = returnId;
    }
    
    const span = document.createElement("span");
    span.className = "todo-readonly";
    span.innerText = todo;

    const buttonModify = document.createElement("button");
    buttonModify.innerText = "✏️";
    buttonModify.addEventListener("click",handleButtonModify);

    const buttonComplete = document.createElement("button");
    buttonComplete.innerText = "✓";
    buttonComplete.addEventListener("click",handleButtonComplete);

    const buttonDelete = document.createElement("button");
    buttonDelete.innerText = "❌";
    buttonDelete.addEventListener("click",handleButtonDeleteReadonly);

    div.appendChild(span);
    div.appendChild(buttonModify);
    div.appendChild(buttonComplete);
    div.appendChild(buttonDelete);
    todoListElement.appendChild(div);
}

function paintModifyTodo(beforeModifyTodo,returnId) { //todo를 수정하는 중인 상태 paint
    const div =  document.createElement("div");
    div.id = returnId;
    
    const form = document.createElement("form");
    form.className = "todo-item";

    const input = document.createElement("input");
    input.type = "text";
    input.className = "todo-input";
    input.value = beforeModifyTodo;

    const buttonSave = document.createElement("button");
    buttonSave.innerText = "저장";
    buttonSave.addEventListener("click",handleButtonSave);

    const buttonDelete = document.createElement("button");
    buttonDelete.innerText = "❌";
    buttonDelete.addEventListener("click",handleButtonDeleteWhileModify);

    form.appendChild(input);
    form.appendChild(buttonSave);
    form.appendChild(buttonDelete);
    div.appendChild(form);
    todoListElement.appendChild(div);

    SendBackProposeNewTodo();
}

function paintProposeNewTodo() { //할일 추가 상자 paint
    const div1 = document.createElement("div");
    div1.className = "todo-item-add";
    div1.addEventListener("click",handleNewTodoElement);

    const div2 = document.createElement("div");
    div2.className = "content";

    const span = document.createElement("span");
    span.innerText = "할 일 추가";

    div2.appendChild(span);
    div1.appendChild(div2);
    todoListElement.appendChild(div1);  
}

function paintCompleted(completed,returnId) { //완료된 todo 상태 paint
    const div = document.createElement("div");
    div.className = "completed-item";
    div.id = returnId

    const span = document.createElement("span");
    span.className = "completed-readonly";
    span.innerText = completed;

    const buttonUp = document.createElement("button");
    buttonUp.className = "completed-button";
    buttonUp.innerText = "⬆";
    buttonUp.addEventListener("click",handleButtonUp);

    div.appendChild(span);
    div.appendChild(buttonUp);
    completedListElement.appendChild(div);
}


/* etc functions*/
function SendBackProposeNewTodo() { //할일 추가 상자가 항상 맨 아래에 있게 하는 역할
    const proposeNewTodoElements = document.querySelectorAll(".todo-item-add");
    if (proposeNewTodoElements.length >1){
        if (proposeNewTodoElements !== null){
            proposeNewTodoElements.remove();
        }
    }
    else {
        for (let proposeNewTodoElement of proposeNewTodoElements) {
            if (proposeNewTodoElement !== null){
                proposeNewTodoElement.remove();
            }
        }
    }

    paintProposeNewTodo();
}

console.log(localStorage.getItem(TODOS_KEY));

if (localStorage[TODOS_KEY] !== undefined) {
    if (localStorage[COMPLETEDS_KEY] !== undefined) {
        for (completedArr of localStorage[COMPLETEDS_KEY])
        {
            console.log(completedArr);
        }
    }
    for (todoArr of localStorage[TODOS_KEY]) {
        console.log(todoArr);
    }
}

initTodoFormElement.addEventListener("submit",handleToDoInitSubmit); //초기 todo에 대한 eventListener

 

 

아래는 html 파일

index.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" />
    <link rel="stylesheet" href="index.css" />
    <title>Document</title>
  </head>
  <body>
    <div class="container todo">
      <h1>오늘의 할 일 Todo</h1>
      <div class="todo-list todo-button">
        <div id="1" class="todo-initDiv">
          <form class="todo-item">
            <input type="text" class="todo-input" placeholder="할 일을 입력하세요">
            <button type = "submit" class="save">저장</button>
          </form>
        </div>
        
      </div>
    </div>

    <div class="container completed" style="margin-top: 3em;">
      <h1>완료한 일 Completed!</h1>
      <div class = "completed-list">

      </div>
    </div>
    <script src="index.js"></script>
  </body>
</html>


<!-- 여러가지 형태의 항목들 -->
<!-- <div class="todo-item"><input type="text" class="todo-input" placeholder="수정할 때 상황." readonly><button>✏️</button><button>✓</button><button>❌</button></div>
        <div class="todo-item"><div class="todo-readonly"><span >기존에 입력되어져 있었던 일</span></div><button>✏️</button><button>✓</button><button>❌</button></div>
        <div class="todo-item"><span class="todo-readonly">기존에 입력되어져 있었던 일</span><button>✏️</button><button>✓</button><button>❌</button></div>
        <div class="todo-item"><input type="text" class="todo-input" value="기존에 입력되어져 있었던 일."><button>저장</button><button>❌</button></div>
        <div class="todo-item"><input type="text" class="todo-input" placeholder="할 일을 입력하세요"><button>저장</button></div>
        <div class="todo-item-add"><div class="content"><span>할 일 추가</span></div></div> -->

 

아래는 css 파일.

index.css

html,
body,
h1 {
  margin: 0;
  padding: 0;
}

h1 {
  text-align: center;
}


.container {
  background-color: white;

  width: 600px;

  margin: 0 auto;
  padding-top: 1em;

  position: relative;
  top: 50%;
}


/**** todo ****/
.todo {

}

.todo-initDiv {

}

.todo-list {
  margin-top: 2em;
  margin-left: 2em;
  margin-right: 2em;
  border:2px solid;
  border-radius: 1em;
  padding: 2em;
}

.todo-item {
  margin-bottom: 1em;
  padding: 0 auto;

  display: flex;
  justify-content: space-between;
  height: 56px;
  
}

.todo-input { 
  background-color: #fff;
  display: flex;
  justify-content: space-between;
  width: 500px;
  margin-top: 0 auto;
  margin-bottom :0 auto;
  height: 50px;
}

.todo-readonly {
  background-color: #fff;
  /* display: flex; */
  justify-content: space-between;
  width: 468px;
  padding-top: 17px ;
  padding-bottom :10px;
  text-align: center;
  border: 2px solid;
}

.todo-item-add {
  margin-bottom: 1em;
  padding: 0 auto;

  display: flex;
  justify-content: space-between;
  height: 56px;

  border:2px dotted; 
  color: lightgray;
  font-size: 1.5em;
}

.todo-item-add .content {
  /* display: flex; */
  justify-content: space-between;
  width: 468px;
  padding-top: 16px ;
  padding-bottom :10px;
  text-align: center;
}

.container .todo-button button{
  background-color: white;
  margin-right: 1px;
  margin-left:2px;
}


/**** completed ****/
.completed {
  
}

.completed-list {
  margin-top: 2em;
  margin-left: 2em;
  margin-right: 2em;
  border:2px solid;
  border-radius: 1em;
  padding: 2em;
}

.completed-item  {
  background-color: black;
  color:white;
  margin-bottom: 1em;
  padding: 0 auto;

  display: flex;
  justify-content: space-between;
  height: 56px;
  
}

.completed-readonly {
  background-color: black;
  color:white;

  justify-content: space-between;
  width: 468px;
  padding-top: 17px ;
  padding-bottom :10px;
  text-align: center;
}

.completed-button {
  background-color: black;
  color:white;
}


/**** 버튼 ****/
button .save {

}


/**** etc ****/
.hidden {
  display: none;
}

 

이정도까지 만들기까지 생각보다 상당히 오래 걸렸다.

한 30시간?

 

localstorage에 저장은 했지만

새로고침 시에 다 사라지는 건 아직 해결하지 못했다.

 

일단 리액트부터 배우고 오자.

'Front-End > JavaScript' 카테고리의 다른 글

[Javascript] async, await  (0) 2023.08.20
[Javascript] Testing code  (0) 2023.08.20
[JavaScript] Todo-List 만들기(1)  (0) 2023.03.30
[JavaScript] 230327 학습일기  (0) 2023.03.29
[JavaScript] 230326 학습일기  (0) 2023.03.27