ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JavaScript] 투두리스트 만들기 - 할 일 생성 기능
    만학도 프로젝트/JavaScript TodoList 2024. 2. 24. 17:48

    지난 글에서 HTML 구조를 잡았었는데요. 

    결과물은 아래 이미지처럼 예쁘진 않지만 일단 필요한 모양들은 다 갖춰진 모습을 하고 있습니다.

     

    너무 보기 힘든 수준이면 예쁘게 다듬는 작업부터 하려고 했었는데, 기능적은 부분을 만드는데 크게 불편함은 없는 수준이라 투두리스트의 기능부터 만들어보려고 해요.

     

    가장 먼저 해야 할 일은 생성 기능이라 생각해서, 생성 기능부터 한번 만들어 보겠습니다. 

     

    1. input#todo-input에 텍스트를 입력하고
    2. button#submit-btn을 클릭하면
    3. ul#todo-listli.todo-item이 추가되도록 해볼거예요.

     

    HTML 수정

    일단은 HTML 수정을 먼저 해보겠습니다.

    1. li.todo-item이 계속 반복될 거라서 li 부분을 template 태그로 빼볼 건데요. 달라지는 부분은 span.item-title이니깐 그 부분을 비워주고 template을 만들어 줄 겁니다.
    2. 그리고 자바스크립트 코드를 따로 js 파일로 빼서 작성할 거니깐 index.js 파일을 불러오는 script 태그도 작성해 줄게요.

    그러면 다음과 같은 HTML 코드가 나오게 됩니다.

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>MHD To Do List</title>
      </head>
      <body>
        <div class="todo-container">
          <h1 class="title">To Do List</h1>
          <form id="todo-form">
            <input type="text" id="todo-input" placeholder="어떤 계획이 있나요?" />
            <button type="submit" id="submit-btn">Add</button>
          </form>
          <ul id="todo-list"></ul>
        </div>
        <!-- li.todo-item 부분 template 태그로 옮기기 -->
        <template id="todo-template">
          <li class="todo-item">
            <input type="checkbox" class="item-checkbox" />
            <span class="item-title"></span>
            <button class="edit-btn">Edit</button>
            <button class="delete-btn">Delete</button>
          </li>
        </template>
        <!-- index.js 파일 불러오는 script 태그 작성 -->
        <script src="index.js"></script>
      </body>
    </html>

    template 태그 관련해서는 제가 따로 블로그에 정리해 둔 게 없긴 한데요, 이 프로젝트 끝난 다음에 따로 한번 정리해 볼게요.

    간단하게 설명하면, 템플릿 태그는 이름에서도 느낄 수 있듯이 미리 틀을 잡아두고 자바스크립트로 동적으로 그 모양의 요소를 편하게 생성할 수 있게 도와주는 태그입니다. 

    그래서 실제로 템플릿 태그를 작성하면, 브라우저에 노출되지도 않아요.

     

     

    코드를 실행해 보면, 이렇게 아이템이 사라진 걸 확인할 수 있죠?

    그럼 이제 같은 html 파일과 같은 위계에 index.js 파일을 만들고 자바스크립트 코드를 작성하러 가봅시다. 

     

    할 일 생성 코드 작성 준비하기

    일단 먼저 필요한 요소들을 변수로 선언해 볼게요.

    const todoForm = document.getElementById('todo-form');
    const todoInput = document.getElementById('todo-input');
    const todoList = document.getElementById('todo-list');
    const todoTemplate = document.getElementById('todo-template');

     

    할 일 생성을 하기 위해 필요한 요소는 이 4가지입니다.

     

    그러고 나서 form 태그에 'submit' 이벤트를 하나 추가해 줄 건데요.

    todoForm.addEventListener('submit', (event) => {});

     

    저는 개인적으로 이벤트를 등록할 때 미리 만들어둔 함수를 등록하는 쪽이 좀 더 가독성이 좋게 느껴져서 이벤트 핸들러를 handleFormSubmit이라는 함수를 따로 만들어서 전달해 볼게요.

    const todoForm = document.getElementById('todo-form');
    const todoInput = document.getElementById('todo-input');
    const todoList = document.getElementById('todo-list');
    const todoTemplate = document.getElementById('todo-template');
    
    const handleFormSubmit = (event) => {
      
    };
    
    todoForm.addEventListener('submit', handleFormSubmit);

     

    할 일 생성 이벤트 핸들러 작성하기

    가장 먼저 할 일은 form 태그의 기본 동작을 막아주는 거예요.

    form 태그는 기본적으로 submit 이벤트에 form 태그 안의 다양한 양식의 데이터들을 요리조리 다루고서 필요한 action을 취한 다음 페이지를 갱신하는 동작이 갖춰져 있어서 그런 기본 동작을 막아줘야 합니다.

    방법은 이벤트 핸들러 첫 번째 파라미터로 넘어오는 event 객체의 preventDefault 메서드를 콜 해주는 거예요.

    //...
    
    const handleFormSubmit = (event) => {
      event.preventDefault();
    };
    
    //...

     

    그다음은 인풋 태그에 값이 작성되어 있는지 확인합시다.

    값이 없으면 굳이 아이템을 추가할 필요가 없으니깐요. 값이 없는 아이템이 생성되는 게 오히려 더 이상한 UX겠죠?

    input요소의 값이 없으면 함수를 빨리 리턴해서 이후 로직들이 동작하지 않도록 해줍시다.

    // ...
    
    const handleFormSubmit = (event) => {
      event.preventDefault();
      // todoInput의 값 추출
      const inputValue = todoInput.value.trim();
      // 값 없으면 빨리 return 하기
      if (inputValue === '') return;
    };
    
    // ...

    그리고 이제 template 태그를 활용해서 가상의 아이템 요소를 생성해 볼 건데요.

    방법은 template 요소의 content 프로퍼티에 접근하고, cloneNode 메서드를 호출할 때 첫 번째 아규먼트로 true 값을 전달해서 호출하면 됩니다.

    // ...
    
    const handleFormSubmit = (event) => {
      event.preventDefault();
      // todoInput의 값 추출
      const inputValue = todoInput.value.trim();
      // 값 없으면 빨리 return 하기
      if (inputValue === '') return;
      const todoItem = todoTemplate.content.cloneNode(true);
    };
    
    // ...

    그런데 이렇게 하면, todoItem이 정확히 li 태그가 아니라, DocumentFragment라는 객체가 되는데요.

    이대로 사용해도 특정 요소에 appenChild를 하면 큰 문제없이 li 태그가 추가되긴 하지만, 그래도 조금 더 명확하게 해주고 싶어서 querySelector 메서드로 정확히 li.todo-item 요소를 잡아주도록 할게요.

    // ...
    
    const handleFormSubmit = (event) => {
      event.preventDefault();
      const inputValue = todoInput.value.trim();
      if (inputValue === '') return;
      
      // 템플릿으로 .todo-item 구조를 복사하고 정확하게 .todo-item 요소 선택하기
      const todoItem = todoTemplate.content.cloneNode(true).querySelector('.todo-item');
    };
    
    // ...

     

    이제 거의 다 완성된 것 같아요!

    잡아둔 todoItem에서 title이 들어갈 자리(span.item-title)에 접근해서 타이틀을 할당하고,

    그렇게 구성된 아이템을 todoList에 추가해 주면 생성기능이 완성이 돼.. 겠지만!

    마지막으로 input의 값을 초기화해줘야 해요! 생성했으면 인풋은 다시 비워줘야겠죠? ㅎㅎ

    그러면 진짜 완성이 됩니다!!

    // ...
    
    const handleFormSubmit = (event) => {
      event.preventDefault();
      const inputValue = todoInput.value.trim();
      if (inputValue === '') return;
    
      const todoItem = todoTemplate.content.cloneNode(true).querySelector('.todo-item');
      // .item-title에 inputValue를 추가
      todoItem.querySelector('.item-title').textContent = inputValue;
      // title이 추가된 todoItem을 todoList에 추가
      todoList.appendChild(todoItem);
    
      // input 초기화
      todoInput.value = '';
    };
    
    // ...

    마무리: Index.js 

    const todoForm = document.getElementById('todo-form');
    const todoInput = document.getElementById('todo-input');
    const todoList = document.getElementById('todo-list');
    const todoTemplate = document.getElementById('todo-template');
    
    const handleFormSubmit = (event) => {
      event.preventDefault();
      const inputValue = todoInput.value.trim();
      if (inputValue === '') return;
    
      const todoItem = todoTemplate.content.cloneNode(true).querySelector('.todo-item');
      todoItem.querySelector('.item-title').textContent = inputValue;
      todoList.appendChild(todoItem);
    
      todoInput.value = '';
    };
    
    todoForm.addEventListener('submit', handleFormSubmit);

    이렇게 코드를 완성하고 나면, 

     

     

    아직 수정이나 삭제도 안되고, 새로고침 하면 다 사라지긴 하지만, 생성 기능은 완성이에요!

     

    당연히 질문이나, 의문점이 드는 부분이라거나 제가 실수를 했다거나, 혹은 좀 더 좋은 방향이 있다면 댓글 부탁드립니다.

    더 좋은 글을 쓰고 제가 성장하는 데에도 큰 도움이 될 거예요! :)

    감사합니다.

    댓글

Designed by BigTop.