In this workshop, we are gonna build a shift tracker app using Blazor. The app will grant users records of the hours spend on each task, edit and save task and history.

Component and Layout

To get ahead start I created a base project for us to work on. Go to the starting-point repo and clone it.

Blazor is compose of two main project, our solution could be composed of more project, is good practice to use a shared project to hold app models.

  • ShitTracker.App: This is the Blazor project. it contains the UI components for the application.
  • ShiftTracker.Server: This is the ASP.NET Core project hosting the Blazor app and also the backend services for the app.

You can run the app by hitting Ctrl-F5. If you get this beautiful screen, then we are ready to start.

If we open Pages/Index.cshtml we can see the code for the home page.

@page "/"

<h1>NativoPlus ShiftTracker</h1>

The index itself is a component, a routable one, notice the “@Page “/” ” ? Blazor will display this component each time the user navigate to “/”.

Display the shifts history

We will start by updateing the home page to display the history of shift. The history will be part of the state of the index component.

Lets add a @functionsbloc to Index.cshtml with a list field to keep track of the history:u

@page "/"
@using ShiftTracker.App.Models

@functions{
    List<Shift> history { get; set; } = new List<Shift>();
}
<h1>NativoPlus ShiftTracker</h1>

The class “Shift” was defined inside a new project named “ShiftTracker.Shared” we added a reference to that project in the “ShiftTracker.App” project then we add “@using ShiftTracker.Shared.Models” to the ShiftTracker.App/_ViewImports.cshtml, this will make that namespace available for all components in this project.

To get a the shift history we are gonna call a API. Blazor provides a preconfigured HttpClient through dependency injection that is already setup with the correct base address. Use the @inject directive to inject an HttpClient into the Index component.

@page "/"
@inject HttpClient HttpClient

The @inject directive essentially defines a new property on the component where the first token specified the property type and the second token specifies the property name. The property is populated for you using dependency injection.

We will like to fetch for the shifts history every time the component is loaded. Blazor component offers some lifecycle we can take advantage of, in this case I will override the OnInitAsync method in the @functions block to retrieve the shift history from the backend.

@functions{
    List<Shift> history { get; set; } = new List<Shift>();
    protected async override Task OnInitAsync()
    {
    
 history = await client.GetJsonAsync<List<Shift>>("/shifts/history");
    }
}

The /shifts/history API is defined by the ShiftsController in the Server project.

Once the component is initialized it will render its markup. Replace the markup in the Index component with the following to list the shifts:

<div class="container is-widescreen">
    <h1>NativoPlus ShiftTracker</h1>
    <div class="row">
        @if (history.Count < 0 || history == null)
        { }else
        { 
@foreach (var shift in history)
            {
                <div class="col-sm-12">
                    <div class="card">
                        <div class="card-body">
                            <h5 class="card-title">@shift.Name</h5>
                            <p class="card-text">Total Hours: @shift.TotalHours</p>     
                        </div>
                    </div>
                </div>
            }
        }
    </div>
</div>

Dosent look to pretty right ? lets orginaze this.

Create a Layout

Now well create a layout for the application.


Layouts in Blazor are also components. They inherit from BlazorLayoutComponent, which defines a Body property that can be used to specify where the body of the layout should be rendered. The layout component for our shirt tracker app is defined in Shared/MainLayout.cshtml.

@inherits BlazorLayoutComponent
 <div class="content ">
        @Body
    </div>

To apply a layout use the @layout directive. Typically this is done in a _ViewImports.cshtml file, which then gets inherited hierarchically. See Pages/_ViewImports.cshtml.

@layout MainLayout

Update the MainLayout component to definea navbar.

@inherits BlazorLayoutComponent
<nav class="navbar navbar-expand-lg navbar-light bg-light">
    <a class="navbar-brand" href="#">NativoPlus ShiftTracker</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
        <div class="navbar-nav">
            <NavLink class="nav-item nav-link " href="/" Match=NavLinkMatch.All>Home</NavLink>
           
        </div>
    </div>
</nav>
    <div class="content ">
        @Body
    </div>

The NavLink component is provided by Blazor. Components can be used from components, which is done by specifying an element with the component’s type name along with attributes for any component parameters.

The NavLink component is the same as an anchor tag, except that it adds an active class if the current URL matches the link address. NavLinkMatch.All means that the link should be active only when it matches the entire current URL (not just a prefix). We’ll examine the NavLink component in more detail in a later session.

With the new layout our app now looks like this:

Next – Modify the shifts