Simple Todo App with Blazor Server and Material Blazor
Tags: dotnet, webdev, blazor
Published: 2020-05-01 10:19:14

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:
- blazor server
- material design https://www.matblazor.com/
- a simple list (no database)

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)
<script src="_content/MatBlazor/dist/matBlazor.js"></script>
<link href="_content/MatBlazor/dist/matBlazor.css" rel="stylesheet" />

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

**A. The main model class for the todos:**
```csharp
public class TodoModel
{
public int Id { get; set; }

public string Todo { get; set; }

public DateTime Deadline { get; set; }

public bool IsCompleted { get; set; }

}
```
**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:**

```csharp
@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;
    }
}
```

**D. Final result:**

![todolist](https://dev-to-uploads.s3.amazonaws.com/i/h3fgr90n5t48i9eg6gja.png)