Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Blazor Web Development Cookbook

You're reading from   Blazor Web Development Cookbook Tested recipes for advanced single-page application scenarios in .NET 9

Arrow left icon
Product type Paperback
Published in Nov 2024
Publisher Packt
ISBN-13 9781835460788
Length 282 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Pawel Bazyluk Pawel Bazyluk
Author Profile Icon Pawel Bazyluk
Pawel Bazyluk
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Chapter 1: Working with Component-Based Architecture 2. Chapter 2: Synchronous and Asynchronous Data Binding FREE CHAPTER 3. Chapter 3: Taking Control of Event Handling 4. Chapter 4: Enhancing Data Display with Grids 5. Chapter 5: Managing Application State 6. Chapter 6: Building Interactive Forms 7. Chapter 7: Validating User Input Forms 8. Chapter 8: Keeping the Application Secure 9. Chapter 9: Exploring Navigation and Routing 10. Chapter 10: Integrating with OpenAI 11. Index 12. Other Books You May Enjoy

Making components generic

A generic class in C# is a class that’s defined with a placeholder type, allowing it to operate with any data type. This flexibility enables the creation of a single class that can adapt its behavior to a variety of data types, enhancing code reusability and efficiency. Generic components in Blazor applications are a similar concept. These components are highly reusable across different contexts and data types. They abstract away specific details, allowing high adaptability to various data or functionalities with minimal changes. This approach significantly reduces code duplication. With that flexibility, you can achieve even higher delivery velocity. The most common scenario where you’ll see generic components shine is repetitive data display, especially grids.

Let’s create a generic Grid component that can render objects of any type by using the provided row template.

Getting ready

Before you start implementing the generic grid, do the following:

  • Create a Recipe08 directory – this will be your working directory
  • Copy the Chapter01/Data directory, which contains the Samples and TicketViewModel objects required for this recipe, next to the working directory

How to do it...

Follow these steps to build and use your generic component:

  1. Create a Grid component. At the top of the file, declare it as generic with the @typeparam attribute:
    @typeparam T
  2. In the @code block of the Grid component, declare parameters for data source and table area customization. The source and row template must be generic:
    @code {
        [Parameter, EditorRequired]
        public IList<T> Data { get; set; }
        [Parameter, EditorRequired]
        public RenderFragment Header { get; set; }
        [Parameter, EditorRequired]
        public RenderFragment<T> Row { get; set; }
    }
  3. For the Grid markup, add a standard HTML table with the Header content rendered where the table header is. For the table body, iterate over Data and render the Row template for each element:
    <table class="grid">
        <thead>
            @Header
        </thead>
        <tbody>
            @foreach (var item in Data)
                @Row(item)
        </tbody>
    </table>
  4. Create a routable Offer component that renders in InteractiveWebAssembly mode and uses the Samples assembly so that Samples can be referenced later:
    @page "/ch01r08"
    @using
        BlazorCookbook.App.Client.Chapters.Chapter01.Data
    @rendermode InteractiveWebAssembly
  5. In the @code block of Offer, implement an Add() placeholder method that writes a simple action confirmation to Console:
    public void Add(TicketViewModel ticket)
       => Console.WriteLine($"Ticket {ticket.Id} added!");
  6. In the markup of the Offer component, use the Grid component and pass in Samples.Tickets as the data source for Grid:
    <Grid Data="@Samples.Tickets">
        @* you will add areas here *@
    </Grid>
  7. Implement the required Header area inside the Grid instance in the Offer markup:
    <Header>
        <tr>
            <td>Ticket code</td>
            <td>Tariff</td>
            <td>Price</td>
            <td></td>
        </tr>
    </Header>
  8. Inside the Grid instance, in the Offer markup, implement the required Row template so that elements of the TicketViewModel type can be rendered:
    <Row>
        <tr>
            <td>@context.Id</td>
            <td>@context.Tariff</td>
            <td>@context.Price</td>
            <td @onclick="() => Add(context)">
                Add to Cart
            </td>
        </tr>
    </Row>

How it works...

We started this recipe by implementing the foundation for creating a generic component. In step 1, we created a Grid component and added the @typeparam attribute at the top. We also specified the name for the parameter type placeholder – much like you would in backend development. We chose to call it T. Blazor recognized @typeparam and now allows us to operate on T inside the component. The IDE will also apply all validations that generic modules require. In step 2, we implemented the @code block of the Grid component by adding a Data parameter that will hold elements to render and two RenderFragment parameters, enabling Grid customization. You can learn more about RenderFragment in the Creating components with customizable content section. Notably, the Data collection isn’t the only generic object. The Row parameter, which contains a row template, is also generic, which means it will expect a data object of type T for initialization. In step 3, we implemented the Grid markup. We rendered the Header value inside the <thead> tags, where the table header normally goes; for the table body, we used a foreach loop to iterate over the Data collection and rendered the Row template for each element.

In step 4, we created a routable Offer component to test our grid. As we expected interactivity, we declared that Offer rendered in InteractiveWebAssembly mode. We also leveraged the Samples object, so we exposed the required assembly with the @using directive. In step 5, we implemented an Add() placeholder method within the @code block of the Offer component to test the Grid component’s interactivity. In step 6, we started implementing the Offer markup. We embedded the Grid component and passed the Samples.Tickets array as the value of the Data parameter. In step 7, we declared the content of Header, which in our case is a set of columns representing TicketViewModel properties and an additional column where we placed action buttons. The real rendering magic happened in step 8. As the Row template expects a TicketViewModel object, we can access TicketViewModel properties in the markup with a @context directive and place them in table columns matching the Header declaration.

There’s more...

The power of the generic component lies in its agnosticism to the data type you’ll use. It simply knows how to construct a template, and where to place customizable content. It’s up to you to define markup to present data properties.

You might find yourself in need of nesting multiple generic components. To do so, you’ll have to define all required RenderFragment parameters. However, a key challenge here is going to be distinguishing each generic context. In that case, you must assign custom names to the context of each generic component using the Context parameter. This parameter is inherited automatically, streamlining the process and enhancing the readability of your code.

Even though our example doesn’t require nesting, we can still leverage the Context naming feature to enhance the code’s readability:

<Grid Data="@Data.Tickets" Context="ticket">
    ...
    <Row>
        <tr>
            <td>@ticket.Id</td>
            ... *
        </tr>
    </Row>
</Grid>

Remember that the more intuitive your code is, the easier it is to navigate and update, especially when you’re working in team environments or returning to the code after some time.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image