티스토리 뷰

목차

  1. 기능정의 및 HTML/CSS
  2. 할 일 추가하기
  3. 할 일 목록에서 할 일 삭제, 완료 처리 구현
  4. 할 일 수정하기
  5. 전체 완료 처리 및 남은 할 일 개수
  6. 하단 버튼 기능 구현

 

1. 할 일 목록에서 할 일 삭제

우리는 이전에 paintTodos() 함수를 통해 HTML을 그렸습니다. 이때, 각각의 할 일들은 'todo-item' 클래스 네임을 가지는 li 요소로 만들어지며, 그 안에 'delBtn' 클래스 네임을 가지는 button 요소가 존재합니다. 각각의 'todo-item'이 만들어질 때마다, 해당 'delBtn'에 'click'에 대한 이벤트 리스너를 등록하여 삭제 기능이 동작하도록 하였습니다.

const paintTodos = () => {
    todoListElem.innerHTML = ''; //todoListElem 요소 안의 HTML 초기화
	const allTodos = getAllTodos() // todos 배열 가져오기

    allTodos.forEach(todo => { 
 			...(생략)
    
        const delBtnElem = document.createElement('button');
        delBtnElem.classList.add('delBtn');
        delBtnElem.addEventListener('click',  () => deleteTodo(todo.id)) // 'click'이벤트 발생 시, 해당 할 일 삭제
        delBtnElem.innerHTML = 'X';

			...(생략)
    })
}

deleteTodo() 함수를 살표봅시다.

'delBtn' 클래스 네임을 가지는 삭제 버튼 요소를 click 하면 deleteTodo() 함수가 실행되고 인자로 todo.id를 받습니다. deleteTodo() 함수는 입력받은 todo의 id 값과 Array filter()를 이용해 삭제하고자 하는 할 일을 제외한 새로운 할 일 목록을 가지는 배열을 만들 수 있고, 이를 setTodos()함수를 통해 기존의 todos 배열을 바꿔줍니다. 그 후, paintTodos() 함수를 통해 삭제된 todos배열로 다시 HTML를 다시 렌더링 합니다.

const deleteTodo = (todoId) => {
    const newTodos = getAllTodos().filter(todo => todo.id !== todoId );
    setTodos(newTodos);
    paintTodos()
}

 

2. 할 일 완료 처리

완료 처리도 삭제 기능과 마찬가지로 'click' 이벤트 리스너 등록을 통해 처리해주면 됩니다. 

const paintTodos = () => {
    todoListElem.innerHTML = ''; //todoListElem 요소 안의 HTML 초기화
    const allTodos = getAllTodos() // todos 배열 가져오기

    allTodos.forEach(todo => { 
 			...(생략)
            
        const checkboxElem = document.createElement('div');
        checkboxElem.classList.add('checkbox');
        checkboxElem.addEventListener('click', () => completeTodo(todo.id)) // 'click'이벤트 발생 시, 완료 처리

			...(생략)
    })
}

체크박스를 'click'하면 checkTodo() 함수가 실행되며, 동작 방식을 삭제 기능과 거의 같습니다. 차이점은 삭제에서는 Array filter()를 사용해서 삭제하고자 하는 할 일을 제외한 배열을 만들었으면, 완료 처리는 Array map()을 사용하여 완료 처리를 하고자 하는 할 일의 isCompleted 값을 토글(true이면 false로, false면 true로) 처리하여 새로운 todos 배열을 저장합니다. 이후 HTML은 paintTodos() 함수를 통해 변경된 todos를 재 렌더링합니다..

const completeTodo = (todoId) => {
    const newTodos = getAllTodos().map(todo => todo.id === todoId ? {...todo,  isCompleted: !todo.isCompleted} : todo )
    setTodos(newTodos);
    paintTodos();
}

 

 

[ 전체 소스 코드 ]

const todoInputElem = document.querySelector('.todo-input');
const todoListElem = document.querySelector('.todo-list');

let todos = [];
let id = 0;

const setTodos = (newTodos) => {
    todos = newTodos;
}

const getAllTodos = () => {
    return todos;
}

const appendTodos = (text) => {
    const newId = id++;
    const newTodos = getAllTodos().concat({id: newId, isCompleted: false, content: text })
    // const newTodos = [...getAllTodos(), {id: newId, isCompleted: false, content: text }]
    setTodos(newTodos)
    paintTodos();
}

const deleteTodo = (todoId) => {
    console.log(todoId);
    const newTodos = getAllTodos().filter(todo => todo.id !== todoId );
    setTodos(newTodos);
    paintTodos()
}

const completeTodo = (todoId) => {
    const newTodos = getAllTodos().map(todo => todo.id === todoId ? {...todo,  isCompleted: !todo.isCompleted} : todo )
    setTodos(newTodos);
    paintTodos();
}

const paintTodos = () => {
    todoListElem.innerHTML = ''; //todoListElem 요소 안의 HTML 초기화
	const allTodos = getAllTodos() // todos 배열 가져오기

    allTodos.forEach(todo => { 
        const todoItemElem = document.createElement('li');
        todoItemElem.classList.add('todo-item');

        todoItemElem.setAttribute('data-id', todo.id );

        const checkboxElem = document.createElement('div');
        checkboxElem.classList.add('checkbox');
        checkboxElem.addEventListener('click', () => completeTodo(todo.id))
    
        const todoElem = document.createElement('div');
        todoElem.classList.add('todo');
        todoElem.innerText = todo.content;
    
        const delBtnElem = document.createElement('button');
        delBtnElem.classList.add('delBtn');
        delBtnElem.addEventListener('click', () =>  deleteTodo(todo.id))
        delBtnElem.innerHTML = 'X';

        if(todo.isCompleted) {
            todoItemElem.classList.add('checked');
            checkboxElem.innerText = '✔';
        }

        todoItemElem.appendChild(checkboxElem);
        todoItemElem.appendChild(todoElem);
        todoItemElem.appendChild(delBtnElem);

        todoListElem.appendChild(todoItemElem);
    })
}

const init = () => {
    todoInputElem.addEventListener('keypress', (e) =>{
        if( e.key === 'Enter' ){
            appendTodos(e.target.value); todoInputElem.value ='';
        }
    })
}

init()

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함