Skip to main content

Todo App

Todo App Project Preview - Add Task Page Screenshot Todo App Project Preview - Main Page Example Screenshot

The Project

A complete Todo App with localStorage for data persistence, developed with vanilla JavaScript, advanced form handling and dynamic user interface. A task management application with complete CRUD functionality.

Source Code

<!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" />
<title>Learn localStorage by Building a Todo App</title>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
<main>
<h1>Todo App</h1>
<div class="todo-app">
<button id="open-task-form-btn" class="btn large-btn">
Add New Task
</button>
<form class="task-form hidden" id="task-form">
<div class="task-form-header">
<button id="close-task-form-btn" class="close-task-form-btn" type="button" aria-label="close">
<svg class="close-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="48px" height="48px"><path fill="#F44336" d="M21.5 4.5H26.501V43.5H21.5z" transform="rotate(45.001 24 24)" /><path fill="#F44336" d="M21.5 4.5H26.5V43.501H21.5z" transform="rotate(135.008 24 24)" /></svg>
</button>
</div>
<div class="task-form-body">
<label class="task-form-label" for="title-input">Title</label>
<input required type="text" class="form-control" id="title-input" value="" />
<label class="task-form-label" for="date-input">Date</label>
<input type="date" class="form-control" id="date-input" value="" />
<label class="task-form-label" for="description-input">Description</label>
<textarea class="form-control" id="description-input" cols="30" rows="5"></textarea>
</div>
<div class="task-form-footer">
<button id="add-or-update-task-btn" class="btn large-btn" type="submit">
Add Task
</button>
</div>
</form>
<dialog id="confirm-close-dialog">
<form method="dialog">
<p class="discard-message-text">Discard unsaved changes?</p>
<div class="confirm-close-dialog-btn-container">
<button id="cancel-btn" class="btn">
Cancel
</button>
<button id="discard-btn" class="btn">
Discard
</button>
</div>
</form>
</dialog>
<div id="tasks-container"></div>
</div>
</main>
<script src="script.js"></script>
</body>

</html>

Time to Stop

In some steps I struggled quite a bit, it was as if my brain was at maximum capacity.
I definitely made a mistake yesterday when, after finishing the predetermined amount of steps (30), I started delving into CSS, as well as continuing in parallel with the English course, also from freeCodeCamp.
I know that the effort required for learning shouldn't be underestimated and that's exactly why in the past I alternated between code and design.

Well, it's time to resume design. I need to have surgery for two inguinal hernias and there are only a few days left, the idea was to go as far as possible with coding, exactly as I've done in these last weeks, and "mentally disconnect" in the post-operative period with design. Apparently, that's not feasible.

I need to alternate between the two activities because I risk lowering the learning level to a threshold so low that it wouldn't even be worth opening freeCodeCamp.

The Responsibility of Learning

All this because I take this path seriously. When I encounter a concept I can't understand, even after studying it in depth, I always remind myself that I can't afford not to assimilate it, because this isn't a hobby, it's my future job. If I don't understand a concept now it will mean I'll waste much more time tomorrow learning it, plus not knowing it equals losing pieces of the mental puzzle I need to think like a developer.

What I Learned

localStorage Mastery:

  • localStorage.getItem() to retrieve persistent data
  • localStorage.setItem() to save data in the browser
  • JSON.parse() and JSON.stringify() for object conversion
  • Data handling when localStorage is empty with || []

Advanced Array Methods:

  • .findIndex() to find the index of specific elements
  • .unshift() to add elements to the beginning of the array
  • .splice() to remove elements from specific positions
  • .forEach() with destructuring for elegant iteration

Complete Form Handling:

  • e.preventDefault() to control form behavior
  • Input validation with empty value checking
  • Form state management (Add vs Update mode)
  • Dynamic form reset after operations

Advanced DOM Manipulation:

  • Template literals for dynamic HTML generation
  • innerHTML for complete content updates
  • parentElement for relative DOM navigation
  • Event handling with function parameters

Modal Dialog System:

  • showModal() and close() for native dialog control
  • Close confirmation handling with change checking
  • Value comparison to detect unsaved changes

Utility Functions:

  • removeSpecialChars() for input sanitization
  • Unique ID generation with timestamp
  • String manipulation with trim(), replace(), split(), join()

State Management:

  • Global state management with currentTask object
  • Synchronization between UI and localStorage
  • Add/Edit pattern with the same form

Reflection

Google UX here I come!


Next Project: Learn Recursion by Building a Decimal to Binary Converter