30 Days of JavaScript: Building a Simple ToDo App with JavaScript — Day 8

30 Days of JavaScript: Building a Portfolio Website — Day 30
30 Days of JavaScript: Building a Simple ToDo App with JavaScript — Day 8

Create a fully functional ToDo app using JavaScript. Master CRUD operations, data persistence with LocalStorage, and practical coding techniques in this step-by-step guide.

Welcome back, JavaScript enthusiasts! Today, we’ll tackle an exciting hands-on project—building a simple ToDo app using JavaScript. This exercise will not only reinforce your understanding of core concepts but also give you practical, real-world coding experience. Let’s dive in and create a fully functional ToDo app!

Table of Contents

Planning and Structuring Your App

Before diving into the code, it’s essential to plan and structure our ToDo app. The app will consist of three core components:

  • An input field for adding new tasks
  • A task list to display tasks
  • Buttons for editing and deleting tasks

With this structure in mind, we’ll implement the app using HTML, CSS, and JavaScript.

Implementing CRUD Operations

CRUD stands for Create, Read, Update, and Delete—operations essential for managing data in any app. We’ll now implement these features in our ToDo app.

Create

Let’s start by creating an input field and a button to add new tasks. Here’s the HTML:

<input type="text" id="task-input" placeholder="Enter a task">
<button id="add-task-btn">Add Task</button>

Now, we’ll add an event listener to handle creating new tasks when the button is clicked:

/**
 * Adds a new task when the button is clicked
 * @param {string} taskText - The text for the new task
 */
const taskInput = document.getElementById('task-input');
const addTaskBtn = document.getElementById('add-task-btn');

addTaskBtn.addEventListener('click', () => {
    const taskText = taskInput.value.trim();
    if (taskText !== '') {
        createTask(taskText);
        taskInput.value = '';
        saveTasks(); // Save to LocalStorage after creating the task
    }
});
Read

To display tasks, we’ll use an unordered list:

<ul id="task-list"></ul>

Next, we’ll create a function to display tasks:

/**
 * Creates and displays a task
 * @param {string} text - The text of the task
 */
const taskList = document.getElementById('task-list');

function createTask(text) {
    const listItem = document.createElement('li');
    listItem.textContent = text;
    addTaskButtons(listItem); // Add edit and delete buttons
    taskList.appendChild(listItem);
}
Update and Delete

To update and delete tasks, we’ll add two buttons: one for editing and one for deleting:

/**
 * Adds edit and delete buttons to a task
 * @param {HTMLElement} listItem - The list item representing the task
 */
function addTaskButtons(listItem) {
    const editBtn = document.createElement('button');
    editBtn.textContent = 'Edit';
    editBtn.addEventListener('click', () => editTask(listItem));

    const deleteBtn = document.createElement('button');
    deleteBtn.textContent = 'Delete';
    deleteBtn.addEventListener('click', () => deleteTask(listItem));

    listItem.appendChild(editBtn);
    listItem.appendChild(deleteBtn);
}

/**
 * Edits a task
 * @param {HTMLElement} listItem - The task item to be edited
 */
function editTask(listItem) {
    const updatedText = prompt('Edit the task', listItem.firstChild.textContent);
    if (updatedText !== null && updatedText.trim() !== '') {
        listItem.firstChild.textContent = updatedText.trim();
        saveTasks(); // Save changes to LocalStorage
    }
}

/**
 * Deletes a task
 * @param {HTMLElement} listItem - The task item to be deleted
 */
function deleteTask(listItem) {
    if (confirm('Are you sure you want to delete this task?')) {
        listItem.remove();
        saveTasks(); // Update LocalStorage after deletion
    }
}

LocalStorage for Data Persistence

To ensure that tasks persist even after refreshing the page, we’ll use LocalStorage. First, let’s create a function to save tasks:

/**
 * Saves tasks to LocalStorage
 */
function saveTasks() {
    const tasks = [];
    const listItems = taskList.getElementsByTagName('li');
    for (let item of listItems) {
        tasks.push(item.firstChild.textContent); // Store task text only
    }
    localStorage.setItem('tasks', JSON.stringify(tasks));
}

We’ll call this function whenever a task is created, updated, or deleted:

// Save tasks after creating a task
createTask(taskText);
saveTasks();

// Save tasks after editing a task
listItem.firstChild.textContent = updatedText.trim();
saveTasks();

// Save tasks after deleting a task
listItem.remove();
saveTasks();

Finally, we’ll load the tasks from LocalStorage when the page loads:

/**
 * Loads tasks from LocalStorage on page load
 */
function loadTasks() {
    const tasks = JSON.parse(localStorage.getItem('tasks'));
    if (tasks) {
        tasks.forEach(task => createTask(task)); // Re-create tasks on load
    }
}

document.addEventListener('DOMContentLoaded', loadTasks); // Load tasks when page loads

Wrapping Up

Here’s the complete code for the ToDo app:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Simple ToDo App</title>
    <style>
        /* Add your custom styles here */
    </style>
</head>
<body>
    <h1>Simple ToDo App</h1>
    <input type="text" id="task-input" placeholder="Enter a task"/>
    <button id="add-task-btn">Add Task</button>
    <ul id="task-list"></ul>

    <script>
    /**
     * References to DOM elements for task input and buttons
     */
    const taskInput = document.getElementById('task-input');
    const addTaskBtn = document.getElementById('add-task-btn');
    const taskList = document.getElementById('task-list');

    /**
     * Event listener to handle adding a new task when the button is clicked
     */
    addTaskBtn.addEventListener('click', () => {
        const taskText = taskInput.value.trim();
        if (taskText) {
            createTask(taskText);   // Create a new task
            saveTasks();            // Save to LocalStorage after task creation
            taskInput.value = '';    // Clear input field after task creation
        }
    });

    /**
     * Creates a new task list item and adds edit/delete buttons
     * @param {string} text - The text of the new task
     */
    function createTask(text) {
        const listItem = document.createElement('li');
        listItem.textContent = text;
        addTaskButtons(listItem);    // Add Edit and Delete buttons to task
        taskList.appendChild(listItem);
    }

    /**
     * Adds Edit and Delete buttons to a task list item
     * @param {HTMLElement} listItem - The list item to add buttons to
     */
    function addTaskButtons(listItem) {
        const editBtn = document.createElement('button');
        editBtn.textContent = 'Edit';
        editBtn.addEventListener('click', () => editTask(listItem));

        const deleteBtn = document.createElement('button');
        deleteBtn.textContent = 'Delete';
        deleteBtn.addEventListener('click', () => deleteTask(listItem));

        listItem.appendChild(editBtn);
        listItem.appendChild(deleteBtn);
    }

    /**
     * Edits the task text after prompting the user
     * @param {HTMLElement} listItem - The task list item to edit
     */
    function editTask(listItem) {
        const updatedText = prompt('Edit the task', listItem.firstChild.textContent);
        if (updatedText) {
            listItem.firstChild.textContent = updatedText.trim();
            saveTasks();    // Save changes after editing the task
        }
    }

    /**
     * Deletes a task list item after confirming with the user
     * @param {HTMLElement} listItem - The task list item to delete
     */
    function deleteTask(listItem) {
        if (confirm('Are you sure you want to delete this task?')) {
            listItem.remove();   // Remove task from DOM
            saveTasks();         // Save the updated task list
        }
    }

    /**
     * Saves the current list of tasks to LocalStorage
     */
    function saveTasks() {
        const tasks = [];
        const listItems = taskList.getElementsByTagName('li');
        for (let item of listItems) {
            tasks.push(item.firstChild.textContent);   // Push task text to array
        }
        localStorage.setItem('tasks', JSON.stringify(tasks));    // Save tasks to LocalStorage
    }

    /**
     * Loads tasks from LocalStorage and displays them on page load
     */
    function loadTasks() {
        const tasks = JSON.parse(localStorage.getItem('tasks'));
        if (tasks) {
            tasks.forEach(task => createTask(task));   // Recreate tasks on page load
        }
    }

    // Load tasks from LocalStorage when the document is loaded
    document.addEventListener('DOMContentLoaded', loadTasks);
    </script>
</body>
</html>
Conclusion

Today’s tutorial walked you through building a simple ToDo app with JavaScript. We covered fundamental concepts like CRUD operations, LocalStorage for data persistence, and DOM manipulation to create, edit, and delete tasks. This practical project serves as an excellent opportunity to reinforce your JavaScript skills with real-world examples.

Remember, the more you practice and experiment with these concepts, the more proficient you will become. Try adding new features like task categories, due dates, or task prioritization to further expand the functionality of your app.

What’s Next?

In Day 9, we’ll explore Regular Expressions in JavaScript. You’ll learn how to match patterns, validate inputs, and manipulate text using powerful regex techniques. Stay tuned for another day of hands-on coding fun!

Next: 30 Days of JavaScript: Regular Expressions in JavaScript — Day 9

Leave a Comment

Your email address will not be published. Required fields are marked *


This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top