본문 바로가기
Coding With Jina/JavaScript

[자바스크립트] ToDoList 만들기 응용 Ver. - 로직

by 진아리♡ 2021. 1. 29.
728x90
반응형

 

 

 

 

input 빈칸에 할일을 적으면 Pending에 리스트로 저장되었다가 ⭕를 누르면 Finished로 넘어가고
❌를 누르면 삭제됨 그리고 Finished 리스트에서 🔁를 누르면 다시 Pending으로 넘어가는 시스템

 

 

 

 

 

 

 

1) HTML - 화면구성

<body>
    <form class="input-form">
        <input type="text" placeholder="Add Task"/>
    </form>

    <div class="pending">
        <h1>Pending</h1>
        <ul class="pending-ul"></ul>
    </div>

    <div class="finished">
        <h1>Finished</h1>
        <ul class="finished-ul"></ul>
    </div>
   

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

 

 

 

2) CSS는 일단 생략

 

 

3) JavaScript - HTML과 연결

const form = document.querySelector(".input-form");
const formInput = form.querySelector("input");
const pendingList = document.querySelector(".pending-ul");
const finishedList = document.querySelector(".finished-ul");

 

 

 

4) JavaScript - 로직

① loadTask( )

- 이 함수는 pending과 finished 공통으로 쓰이는 함수

- pending과 finished가 같은 맥락이므로 pending으로만 설명함

- 로컬스토리지의 value값을 변수 pendingValue에 저장 

- pendingValue가 null이 아니라면의 조건문으로 parseTask 변수에 객체로 변환하여 저장

- parseTask 변수에는 pendingValue의 정보를 각각 배열객체로 저장되어있음

- parseTask 의 배열 요소 마다 paintPending 함수를 실행함

//로컬스토리지의 key값
const PENDING = "PENDING",
    FINISHED = "FINISHED";    

//맨처음 실행되는 함수    
function loadTask(){
    //로컬스토리지 value 값을 변수 pendingValue와 finishedValue에 각각 저장
    const pendingValue = localStorage.getItem(PENDING);
    const finishedValue = localStorage.getItem(FINISHED);


    if(pendingValue !== null){
        // JSON.parse : 인수로 전달받은 문자열을 자바스크립트 객체로 변환하여 반환하는 메서드
        // 여기서는 pendingValue가 string이므로 객체로 변환하여 parsedTask에 저장
        const parsedTask = JSON.parse(pendingValue);

        //헷갈리면 콘솔찍어보기
        // 찍어보면 parsedTask는 배열 객체라는 것을 알 수 있다.
        console.log("parsedTask = "+parsedTask);
        console.log(parsedTask);

        // forEach : 주어진 함수를 배열 요소마다 실행 
        // 여기서 toDo는 parsedTask의 배열 요소들
        parsedTask.forEach(function (toDo) {

        // data 형태로 저장되어 있는 parsedTask 안에 있는 text를 불러온것
        paintPending(toDo.text); 

           
        });
    }

    if(finishedValue !== null){
        const parsedTask = JSON.parse(finishedValue);
        parsedTask.forEach(function (toDo) {
            paintFininshed(toDo.text); 
        }); 
    }
}    


function init(){
    loadTask();
    
    //input에서 엔터를 눌렀을때 실행되는 함수
    form.addEventListener("submit", handleSubmitPending);
}

init();

 

 

② handleSubmitPending( )

- form 태그 안에 있는 input에 이름을 쓰고 엔터를 눌렀을때 실행되는 함수

- form.addEventListener("submit", handleSubmitPending); 로 인해 실행되는 함수

- 이번 로직에서는 input에 쓰면 무조건 pending에 먼저 저장되므로 이 함수는 pending에만 적용

//input에 쓴 text를 savePending과 paintPending 함수에 인자로 보내는 함수
function handleSubmitPending(event){
    
    //기본 input의 디폴트값으로 엔터를 누르면 자동으로 어딘가 보내지는 기능을
    //중지시키는 메서드
    event.preventDefault();

    //input에 쓴 text를 currentValue에 저장하고 
    const currentValue = formInput.value;

    //함수 인자로 보낸다.
    savePending(currentValue);
    paintPending(currentValue);

    //그리고 input의 빈칸은 다시 비워지게 만듬
    formInput.value="";
}

 

 

③ paintPending( )

- handleSubmitPending( ) 함수에서 currentValue를 인자로 받아와서 loadTask( )함수로 인해 배열 요소마다 함수 실행

- 로컬스토리지에 저장된 value 배열 요소를 리스트로 만들어 출력하는 함수 

// 모든 함수 가장 위에 위치하도록 해야함
// 할일목록은 배열이 되어야 여러개를 저장할 수 있으므로
//pending은 배열로 생성 
let pending = [];


//로컬스토리지 value값을 화면에 출력하는 함수
function paintPending(text){
    const li = document.createElement("li"); // li 태그를 만들어서 변수에 할당
    const passBtn = document.createElement("button"); // button 태그를 만들어서 변수에 할당
    const delBtn = document.createElement("button"); // button 태그를 만들어서 변수에 할당
    const span = document.createElement("span"); // span 태그를 만들어서 변수에 할당


    //pending.length는 pending 객체 안 배열 요소의 갯수를 의미함
    //예를 들어 input에 숨쉬기와 밥먹기를 입력해서 넣어놨다면
    //pending.length는 2가 됨
    const newId=pending.length+1;
    
    //id가 0부터 시작하므로 1부터 시작하게 하기 위해서 1을 더해준것
    //const newId=pending.length;
    //console.log("아이디 = "+newId);

    
    delBtn.innerHTML="❌"; // 버튼의 텍스트는 "❌"로 설정
    delBtn.addEventListener("click",delPending); //❌ 버튼을 누르면 delPending 함수 실행
    passBtn.innerHTML="⭕"; // 버튼의 텍스트는 "⭕"로 설정
    passBtn.addEventListener("click",moveToFinished); //⭕ 버튼을 누르면 moveToFinished 함수 실행
    
    span.innerText=text;// 사용자가 입력한 텍스트가 span태그의 텍스트가 되도록 설정
    li.appendChild(span); // li 태그의 자식 태그로 span 태그 삽입
    
    li.id=newId; // li태그의 id 속성을 object의 id와 같게 함.
    li.appendChild(delBtn);// li 태그의 자식 태그로 버튼을 삽입
    li.appendChild(passBtn);// li 태그의 자식 태그로 버튼을 삽입
    pendingList.appendChild(li);// 위에서 설정한 li 태그들을 최종적으로 pendingList에 삽입

    //할일을 pending 배열에 추가해야하므로 객체로 만들어서 추가함
    const toDoObj={
        text: text, 
        id: newId  
    };

    pending.push(toDoObj);  // toDos라는 Array 안에 toDoObj 객체를 넣음.
    savePending();
}

 

 

④ savePending( )

- handleSubmitPending( ) 함수 안 지역변수 currentValue를 인자로 받아 로컬스토리지 value값으로 저장하는 함수

- JSON.stringify 에 대한 설명 : coding-with-jina.tistory.com/125?category=781130 

//로컬스토리지 value 값에 저장하는 함수
function savePending(){

    //JSON.stringify : 블로그에 설명된 링크 볼것
    localStorage.setItem(PENDING, JSON.stringify(pending));
}



delPending( ) 

- 사용자가 선택한 요소의 로컬스토리지 pending의 value값을 지우고 출력된 리스트에도 삭제되는 함수

//사용자가 선택한 요소의 로컬스토리지 pending의 value값을 지우고 출력된 리스트에도 삭제되는 함수
function delPending(event){
    
    // event.target : 블로그 링크 설명
    // 클릭된 버튼을 할당
    const btn = event.target;

    // console.dir(event.target) // 이 방법으로 event.target의 부모 노드를 확인가능
    // event.target.parentNode 
    /* event.target.parentNode 
        -여러 개의 버튼 중 어느 버튼이 클릭됐는지 알려줌 
        - 클릭된 버튼 태드의 부모 태그를 불러옴 */
   
    const li = btn.parentNode; // 할당된 버튼의 부모 태그(li)를 할당
    pendingList.removeChild(li); // 해당 태그 삭제
    
    
    /*filter 함수는 array의 모든 요소들에 함수를 실행하고, 
    값이 true인 것들만 가지고 새로운 array를 만들어 반환함 */
    const cleanTask = pending.filter(function(toDo){
       return toDo.id !== parseInt(li.id);
    });

    //값이 true인 것들만 가지고 새로운 array를 만들어 반환한 것들만 저장된 cleanTask 변수를
    //다시 pending에 저장
    pending=cleanTask;
    savePending();
}

 

 

moveToFinished( )

- 버튼을 누르면 finished 리스트로 옮겨지는 기능

- const span1 = event.path[1].childNodes[0].innerHTML;

- [참고] event.path 에 대한 설명 : coding-with-jina.tistory.com/132

//버튼을 누르면 finished 리스트로 옮겨지는 기능
function moveToFinished(event){

    //event.path[1] 블로그 링크로 설명
   const span1 = event.path[1].childNodes[0].innerHTML;
   
    console.log(span1);
    delPending(event);
    paintFininshed(span1);
}

 

⑦ finished 영역

- ③~④번까지의 같은 의미의 코드를 finished에도 똑같이 적용해서 작성

//----finished---------------------------------------------------------

//3번 
//로컬스토리지에 저장된 value 배열 요소를 리스트로 만들어 출력하는 함수 
function paintFininshed(text){
    const li = document.createElement("li");
    const delBtn = document.createElement("button");
    const passBtn = document.createElement("button");
    const span = document.createElement("span");
    const newId=finished.length+1;
    delBtn.innerHTML="❌";
    delBtn.addEventListener("click",delFinished);
    passBtn.innerHTML="🔁";
    passBtn.addEventListener("click",moveToPending);
    span.innerText=text;
    li.appendChild(span);
    li.id=newId;
    li.appendChild(delBtn);
    li.appendChild(passBtn);
    finishedList.appendChild(li);
    
    const toDoObj={
        text: text, 
        id: newId  
    };
    finished.push(toDoObj);
    saveFinished();

}


//4번 
//currentValue를 인자로 받아 로컬스토리지 value값으로 저장하는 함수
function saveFinished(){
    localStorage.setItem(FINISHED, JSON.stringify(finished));
}


//5번
//사용자가 선택한 요소의 로컬스토리지 finished의 value값을 지우고 출력된 리스트에도 삭제되는 함수
function delFinished(event){
    const btn = event.target;
    const li = btn.parentNode;
    finishedList.removeChild(li);

    const cleanFinished = finished.filter(function(toFinished){
       return toFinished.id !== parseInt(li.id);
    });
    finished=cleanFinished;
    saveFinished();
}


//6번
//버튼을 누르면 pending 리스트로 옮겨지는 기능
function moveToPending(event){
    const span2 = event.path[1].childNodes[0].innerHTML;
    console.log(span2);
    delFinished(event);
    paintPending(span2);
}

 

5) 결과

 

 

 

직접 실행해보세요😀

jina-choi.github.io/coding-with-jina/mini_project/todolist_Upgrade_Ver/index.html

 

Day7

 

jina-choi.github.io

 

728x90
반응형