DEV Community

Akram Khan
Akram Khan

Posted on

I create a Todo Application in Typescript With Save Todos in Local Storage

we are use a vanilla vite project with typescript in this for understanding typescript and use a localstorage for store the todos.

<!doctype html>
<html lang="en">

<head>
     <meta charset="UTF-8" />
     <link rel="icon" type="image/svg+xml" href="/vite.svg" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
     <title>Vite + TS</title>
     <link rel="stylesheet" href="./src/style.css">
</head>

<body>
     <div id="app">

          <div class="container">

               <h1>My Todo List</h1>

          <form id="myForm">
               <input required type="text" id="inputTodo" placeholder="Enter Todo">
               <button type="submit" id="btnSubmit">Add</button>
          </form>

          <div class="todos-container">
               <!-- <div class="todo-item">
                    <input id="isComplete" type="checkbox">
                    <p id="todoText">my today todo</p>
                    <button id="btnDelete">X</button>
               </div> -->
          </div>

     </div>

</div>

     <script type="module" src="/src/main.ts"></script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode
.container{
     max-width: 700px;
     margin-inline: auto;
     display: flex;
     align-items: center;
     justify-content: center;
     flex-direction: column;
}

form #inputTodo{
     padding: 8px 15px;
}

form #btnSubmit{
     padding: 8px 15px;
}

.todos-container{
     padding: 10px;
     width: 100%;
     width: fit-content;
}

.todo-item{
     padding: 5px;
     border: 1px solid gray;
     gap: 20px;
     width: 100%;
     display: flex;
     align-items: center;
}

.textCut{
     text-decoration: line-through;
}
Enter fullscreen mode Exit fullscreen mode
interface Todo{
     content: string,
     isComplete: boolean,
     readonly id:string
}

let todos:Todo[] = [];

const todosContainer = document.querySelector('.todos-container')!;

function genrateTodo(id: string, content:string, isComplete:boolean){
     const itemContainer:HTMLDivElement = document.createElement('div');
     itemContainer.classList.add('todo-item');

     // checkbox
     const checkbox: HTMLInputElement = document.createElement('input');
     checkbox.type = "checkbox";
     checkbox.checked = isComplete
     checkbox.onchange = () => {
          todos.find(todo => {
               if(todo.id === id) todo.isComplete = checkbox.checked;

               // save updated todo
               localStorage.setItem('todos', JSON.stringify(todos));
          })
          todoText.className = checkbox.checked ? 'textCut' : '';
     }

     // paragraph content
     const todoText:HTMLParagraphElement = document.createElement('p');
     todoText.innerHTML = content;
     todoText.className = isComplete ? 'textCut' : '';

     // delete button
     const btnDelete: HTMLButtonElement = document.createElement('button');
     btnDelete.textContent = 'X';
     btnDelete.onclick = () => {
          todos = todos.filter(todo => todo.id !== id);
          localStorage.setItem('todos', JSON.stringify(todos));
          renderTodos(todos);
     }

     itemContainer.append(checkbox, todoText, btnDelete);
     todosContainer.appendChild(itemContainer);

}

// add todo
const form = document.getElementById('myForm')!;
form.onsubmit = (e: SubmitEvent) => {
     e.preventDefault();
     const inputElement = document.getElementById('inputTodo') as HTMLInputElement;
     let value:string = inputElement.value;

     const newTodo:Todo = {
          id: String(Math.random() * 1000),
          content: value,
          isComplete: false
     }

     todos.push(newTodo);
     inputElement.value = "";

     localStorage.setItem('todos', JSON.stringify(todos));

     renderTodos(todos);
}


function renderTodos(todos: Todo[]){
     todosContainer.innerHTML = "";
     todos.forEach(todo => {
          genrateTodo(todo.id, todo.content, todo.isComplete);
     })
}

const jsonTodos = localStorage.getItem('todos')!;
const storedTodos : Todo[] = JSON.parse(jsonTodos);
todos = storedTodos;
renderTodos(todos);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)