Display a Heroes List

Attributions

This tutorial is a derivative of the Angular Tour Of Heroes App and Tutorial under CC BY 4.0..

In this page, you'll expand the Tour of Heroes app to display a list of heroes, and allow users to select a hero and display the hero's details.

Create mock heroes

You'll need some heroes to display. Eventually you'll get them from a remote data server. For now, you'll create some mock heroes and pretend they came from the server.

  1. Open the app.css file and add the following code:

    .heroes {
        margin: 0 0 2em 0;
        list-style-type: none;
        padding: 0;
        width: 15em;
    }
    
    .heroes li {
        cursor: pointer;
        position: relative;
        left: 0;
        background-color: #EEE;
        margin: .5em;
        padding: .3em 0;
        height: 2em;
        border-radius: 4px;
    }
    
        .heroes li:hover {
            color: #607D8B;
            background-color: #DDD;
            left: .1em;
        }
    
        .heroes li.selected {
            background-color: #CFD8DC;
            color: white;
        }
    
            .heroes li.selected:hover {
                background-color: #BBD8DC;
                color: white;
            }
    .heroes a {
        color: #333;
        text-decoration: none;
        position: relative;
        display: block;
        width: 250px;
    }
    
    .heroes .badge {
        display: inline-block;
        font-size: small;
        color: white;
        padding: 0.8em 0.7em 0 0.7em;
        background-color: #405061;
        line-height: 0.8em;
        position: relative;
        left: -1px;
        top: -4px;
        height: 2.4em;
        margin-right: .8em;
        border-radius: 4px 0 0 4px;
    }
    

    Note: in the Angular version of the tutorial, component-specific CSS styles go into separate files which are referenced by the component. This level of CSS encapsulation or isolation is not currently available in Blazor, but is an open issue and looks to be included in .NET 5.

  2. Alter the @code block in the Heroes component to look like this:

    @code {
        List<Hero> heroes { get; set; } = new List<Hero>{
            new Hero { Id = 11, Name = "Dr Nice" },
            new Hero { Id = 12, Name = "Narco" },
            new Hero { Id = 13, Name = "Bombasto" },
            new Hero { Id = 14, Name = "Celeritas" },
            new Hero { Id = 15, Name = "Magneta" },
            new Hero { Id = 16, Name = "RubberMan" },
            new Hero { Id = 17, Name = "Dynama" },
            new Hero { Id = 18, Name = "Dr IQ" },
            new Hero { Id = 19, Name = "Magma" },
            new Hero { Id = 20, Name = "Tornado" }
        };
    }
    
  3. Change the markup section in the Heroes component to look like this:

    @page "/heroes"
    
    <h2>My Heroes</h2>
    <ul class="heroes">
        @foreach (var hero in heroes)
        {
            <li>
                <span class="badge">@hero.Id</span> @hero.Name
            </li>
        }
    </ul>
    

    The code uses a standard C# foreach loop embedded in the HTML via Razor to iterate over the collection of heroes and output them as list items in an unordered list.

  4. Run the application and navigate to /heroes. The resulting page should look like this:
    Displaying a list
    As you hover over each hero, you will notice that it changes appearance.
    Hover Style

Master/Detail

When the user clicks a hero in the master list, the component should display the selected hero's details at the bottom of the page. In this section, you'll listen for the hero item click event and update the hero detail.

  1. Alter the markup section in the Heroes component to add a click event binding:

    @page "/heroes"
    
    <h2>My Heroes</h2>
    <ul class="heroes">
    @foreach (var hero in heroes)
    {
        <li @onclick=@(() => onSelect(hero))>
            <span class="badge">@hero.Id</span> @hero.Name
        </li>
    }
    </ul>
    

    The click event binding takes the current hero being iterated over, and passes it to an onSelect event handler, which is defined next.

  2. Add the following code to the end of the @code block:

    Hero selectedHero { get; set; }
    
    void onSelect(Hero hero)
    {
        selectedHero = hero;
    }
    

    The event handler takes the hero instance and assigns it to the newly added selectedHero property.

Add a details section

Currently, you have a list in the component template. To click on a hero on the list and reveal details about that hero, you need a section for the details to render in the template. Add the following to Heroes component beneath the list section:

@if (selectedHero != null)
{
    <h2>@selectedHero.Name.ToUpper() Details</h2>
    <div><span>Id: </span>@selectedHero.Id</div>
    <div>
        <label>
            Name:
            <input @[email protected] />
        </label>
    </div>
}

After the browser refreshes, the list of names reappears. The details area is blank. Click a hero in the list of heroes and its details appear. The app seems to be working again. The heroes appear in a list and details about the clicked hero appear at the bottom of the page:

Display the list

Why it works

When selectedHero is null, the if statement doesn't execute, so no HTML is rendered for the selectedHero details. There are no selectedHero bindings to consider.

When the user picks a hero, selectedHero has a value and the HTML is rendered accordingly.

Style the selected hero

It's difficult to identify the selected hero in the list when all <li> elements look alike.

If the user clicks "Magneta", that hero should render with a distinctive but subtle background color like this:

Selected hero

That selected hero colouring is the work of the .selected CSS class in the styles you added earlier. You just have to apply the .selected class to the <li> when the user clicks it.

Being able to embed C# expressions via Razor into HTML makes it easy to add and remove a CSS class conditionally. Just add a conditional or ternary operator to the attribute you want to set conditionally:

class="@(hero == selectedHero ? "selected" : "")"

This code is a shorthand representation of an if...else statement. It says, "if the current hero is the selectedHero, render "selected" as a value for the class attribute, else render an empty string".

The finished <li> looks like this:

<li @onclick=@(e => onSelect(hero)) class="@(hero == selectedHero ? "selected" : "")">

Summary

  • The Tour of Heroes app displays a list of heroes in a Master/Detail view.
  • The user can select a hero and see that hero's details.
  • You used foreach to display a list.
  • You used if to conditionally include or exclude a block of HTML.
  • You can toggle a CSS style class with embedded Razor.

Previous: The Hero Editor

Last updated: 2/15/2023 9:03:49 AM

Latest Updates

© 2023 - 2024 - Mike Brind.
All rights reserved.
Contact me at Mike dot Brind at Outlook.com