Skip to content

ToDo List App Tutorial Part 6: Deleting ToDo Items

Andrei Fangli edited this page Jul 4, 2021 · 4 revisions

With ToDo List App Tutorial Part 5: Editing a ToDo Item we are now able not only to view and add todo items in our list, we can edit and progress them as well. This is good progress, as we complete more items it's undoubtedly going to get crowded. We will now add the option to delete an item from their edit view, with a confirmation message.

First we will declare the delete method on the edit form view model along side the deleted event.

private readonly _deleted: DispatchEvent = new DispatchEvent();

public get deleted(): IEvent {
    return this._deleted;
}

public delete(): void {
    if (this._itemIndex !== undefined) {
        const todoItems: ToDoItem[] = JSON.parse(localStorage.getItem("todo-items") || "[]");
        todoItems.splice(this._itemIndex, 1);
        localStorage.setItem("todo-items", JSON.stringify(todoItems));

        this._deleted.dispatch(this);
    }
}

Next, we will enrich the edit form with a state that tells us whether we should display the confirmation or not. We will include the onDelete callback as well.

import React, { useCallback, useEffect, useRef, useState } from "react";
import { watchEvent } from "react-model-view-viewmodel";
import { EditToDoItemViewModel } from "../view-models/edit-todo-item-view-model";
import { ToDoItemForm } from "./todo-item-form";

export interface IEditToDoItemFormProps {
    readonly itemIndex: number;
    readonly onSave?: () => void;
    readonly onDelete?: () => void;
    readonly onCancel?: () => void;
}

export function EditToDoItemForm({ itemIndex, onSave, onDelete, onCancel }: IEditToDoItemFormProps): JSX.Element {
    const { current: viewModel } = useRef(new EditToDoItemViewModel());

    const [showDeleteConfirmation, setShowDeleteConfirmation] = useState(false);

    const editCallback = useCallback(() => { viewModel.save(); }, []);
    const deleteCallback = useCallback(() => { viewModel.delete(); }, []);
    const cancelCallback = useCallback(() => { onCancel && onCancel(); }, []);
    const showDeleteConfirmationCallback = useCallback(() => setShowDeleteConfirmation(true), []);
    const hideDeleteConfirmationCallback = useCallback(() => setShowDeleteConfirmation(false), []);

    watchEvent(viewModel.saved, () => { onSave && onSave(); })
    watchEvent(viewModel.deleted, () => { onDelete && onDelete(); })

    useEffect(() => { viewModel.load(itemIndex) }, [itemIndex]);

    return (
        <>
            <ToDoItemForm form={viewModel.form} />
            {
                !showDeleteConfirmation && <div>
                    <button onClick={editCallback}>Edit</button>
                    <button onClick={cancelCallback}>Cancel</button>
                    <button onClick={showDeleteConfirmationCallback}>Delete</button>
                </div>
            }
            {
                showDeleteConfirmation && <div>
                    <p>Deleting an item is permanent, please confirm your action.</p>
                    <button onClick={deleteCallback}>Delete</button>
                    <button onClick={hideDeleteConfirmationCallback}>Cancel</button>
                </div>
            }
        </>
    );
}

The final step, providing an onDelete callback in the todo list component.

export function ToDoList(): JSX.Element {
    const [selectedIndex, setSelectedIndex] = useState<number | undefined>(undefined);
    const [showAddForm, setShowAddForm] = useState(false);

    const { current: viewModel } = useRef(new ToDoListViewModel());
    watchCollection(viewModel.items);

    const showAddFormCallback = useCallback(() => { setShowAddForm(true) }, []);

    const reloadItems = useCallback(() => { setShowAddForm(false); setSelectedIndex(undefined); viewModel.load(); }, [viewModel]);

    useEffect(() => { viewModel.load(); }, []);

    if (selectedIndex !== undefined)
        return (
            <EditToDoItemForm itemIndex={selectedIndex} onSave={reloadItems} onDelete={reloadItems} onCancel={reloadItems} />
        );
    else
        return (
            <>
                {!showAddForm && <button onClick={showAddFormCallback}>Add</button>}
                {showAddForm && <AddToDoItemForm onSave={reloadItems} onCancel={reloadItems} />}
                <div className="todo-list">
                    {viewModel.items.map((item, index) => <ToDoListItem key={index} item={item} selectItem={() => setSelectedIndex(index)} />)}
                </div>
            </>
        )
}

That's it for this part, it was easy enough. We are nearly finished next up we will be adding validation in ToDo List App Tutorial Part 7: Adding Form Validation.

Clone this wiki locally