DEV Community

Cover image for Simple Todo App with Blazor Server and Material Blazor
Zoltan Halasz
Zoltan Halasz

Posted on

Simple Todo App with Blazor Server and Material Blazor

In order to make my journey in C# more interesting, I insert small projects where I can learn new things. The new target is now Blazor Server, a cool new Web Technology from Microsoft.

I am trying to find small things to learn and add them to a bigger project later this year, perhaps.
My main tutors on the net were Tim Corey, and maybe Nick Chapsas for this topic. You can search them on youtube, they have great content.

The new application I have created is a regular todo app which uses:

Prerequisites:

  • asp.net core 3.1 installed on your machine
  • intermediate C# and html

Code is under:
https://github.com/zoltanhalasz/TodoList_BlazorServer.git

The application is live: https://todolist-blazorserver.zoltanhalasz.net/todos

You can add material design to a blazor server project:

  • Install-Package MatBlazor
  • Add @using MatBlazor in main _Imports.razor
  • add to _Host.cshtml (head section)

The toaster is added to the todo page: see instructions at: https://www.matblazor.com/Toast

A. The main model class for the todos:

public class TodoModel
{
public int Id { get; set; }

public string Todo { get; set; }

public DateTime Deadline { get; set; }

public bool IsCompleted { get; set; }

}
Enter fullscreen mode Exit fullscreen mode

B. The layout:
Please read the below examples
https://www.matblazor.com/TextField
https://www.matblazor.com/Checkbox
https://www.matblazor.com/DatePicker
https://www.matblazor.com/Button
See list of icons available:
https://www.matblazor.com/Icon
Toast, see tutorial example:
https://www.matblazor.com/Toast

C. The code-behind:

@page "/todos"
@inject IMatToaster Toaster
@using TodoList_BlazorServer.Data


<h1>Todo Manager App</h1>

<div class="row">
    <div class="col-md-4">
        <MatTextField @bind-Value="@myTodoText" Label="Add todo task here"></MatTextField>
    </div>
    <div class="col-md-4">
        <MatDatePicker @bind-Value="@myDeadline"></MatDatePicker>
    </div>
    <div class="col-md-4">
        <MatButton Raised="true" Icon="playlist_add" OnClick="@Click">Add Todo</MatButton>
    </div>
</div>

@if (TodoList != null && TodoList.Count>0)
{
    <table class="table">
        <thead>
            <tr>
                <th>Ready?</th>
                <th>Description</th>
                <th>Deadline</th>
                <th>Complete</th>
                <th>Delete</th>
                <th>Edit</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var td in TodoList)
            {
            <tr>
                <td>
                    <MatCheckbox @bind-Value="@td.IsCompleted" Disabled="true"></MatCheckbox>
                </td>
                <td>@td.Todo</td>
                <td>@td.Deadline.ToShortDateString()</td>
                <td><MatButton Icon="done" Outlined="true" @onclick="@(e=> completeItem(td.Id))">Complete</MatButton></td>
                <td><MatButton Icon="delete" Outlined="true" @onclick="@(e=> deleteItem(td.Id))">Delete</MatButton></td>
                <td><MatButton Icon="edit" Outlined="true" @onclick="@(e=> editItem(td.Id))">Edit</MatButton></td>
            </tr>
            }
        </tbody>
    </table>
}

@code {
    private List<TodoModel> TodoList = new List<TodoModel>();
    string myTodoText = null;
    DateTime? myDeadline;
    int editedID = 0;


    private void Click(MouseEventArgs e)
    {
        if (myTodoText == null)
        {
            Toaster.Add("Cannot add empty values", MatToastType.Warning, "Todo List", null);
            return;
        }

        if (editedID == 0)
        {              
            var myTodoItem = new TodoModel()
            {
                Id = TodoList.Count() + 1,
                Deadline = myDeadline == null ? DateTime.Now.AddDays(1) : ((DateTime)myDeadline),
                Todo = myTodoText,
                IsCompleted = false
            };
            TodoList.Add(myTodoItem);
            myTodoText = null;
            myDeadline = null;
            Toaster.Add("New todo added.", MatToastType.Info, "Todo List", null);
        }
        else
        {
            var myTodo = TodoList.FirstOrDefault(x => x.Id == editedID);
            myTodo.Todo = myTodoText;
            myTodo.Deadline = myDeadline == null ? DateTime.Now.AddDays(1) : ((DateTime)myDeadline);

            myTodoText = null;
            myDeadline = null;
            Toaster.Add("Todo edit finished.", MatToastType.Info, "Todo List", null);
            editedID = 0;
        }

    }

    void deleteItem(int id)
    {
        var myTodo = TodoList.FirstOrDefault(x => x.Id == id);
        TodoList.Remove(myTodo);
        Toaster.Add("Todo removed.", MatToastType.Info, "Todo List", null);
    }

    void completeItem(int id)
    {
        var myTodo = TodoList.FirstOrDefault(x => x.Id == id);
        myTodo.IsCompleted = !myTodo.IsCompleted;
        Toaster.Add("Todo status changed.", MatToastType.Info, "Todo List", null);
    }

    void editItem(int id)
    {
        var myTodo = TodoList.FirstOrDefault(x => x.Id == id);
        myTodoText = myTodo.Todo;
        myDeadline = myTodo.Deadline;
        editedID = id;
    }
}
Enter fullscreen mode Exit fullscreen mode

D. Final result:

todolist

Discussion (2)

Collapse
hermetheus profile image
Allan

Zoltan, Thanks for this! It's a nice blazor start!

Collapse
zoltanhalasz profile image
Zoltan Halasz Author

I'm also learning, and try to share my experience. Happy to help.