Overview of Blazor Grid Templates

Overview of Blazor Grid Templates

In this article we'll see an overview of what templates are available and simple use cases. We'll use these as building blocks to see just how dynamic a Blazor grid can be when using templates for advanced ideas like custom editors and master-detail views.

Originally published by Ed Charbeneau at https://www.telerik.com     

Using a template in an application implies that you're creating a custom experience for your user by leveraging a component or framework you're working with. Because the Telerik UI for Blazor components are native, built from the ground up using the Blazor framework, it can tap directly in to Blazor's best features. Grid component templates can fully utilize the HTML, Razor, and components to completely customize the user experience.

In this article we'll see an overview of what templates are available and simple use cases. We'll use these as building blocks to see just how dynamic a Blazor grid can be when using templates for advanced ideas like custom editors and master-detail views.

Template Types

There are currently three types of templates available for the Blazor grid: column Template, Editor Template, and Row Template. Each has very specific uses and are powerful tools for adapting the grid to your specific needs. Let's start with a quick introduction to each template type.

Column Template

By default, the grid renders the value of the field in the column exactly as it's provided from the data source. We can override this behavior by using a column Template which allows us to take control over the rendering of the object within the column. The Template provides the entire object currently bound to the row in which the column exists, and this object is the template's context. Through the Template we can apply custom formatting, insert additional HTML and images, and display Razor Components using any value from the context.

<TelerikGridColumn Field="@(nameof(SampleData.Name))" Title="Employee Name">
   <Template>
      Employee name is: @((context as SampleData).Name)
   </Template>
</TelerikGridColumn>

The column Template is visible when the current row is not in edit mode. To customize the grid's editing experience we'll use the EditorTemplate.

Editor Template

The EditorTemplate is a template that bound to the editing context. The EditorTemplate defines the inline template or component that will be rendered when the user is editing the field. Although the EditorTemplate acts much like the column Template, it is only shown when the given row is in edit mode.

<TelerikGridColumn [email protected](Employee.VacationDays) Title="Position">
   <EditorTemplate>
       @{
           var employeeToUpdate = context as Employee;
                      <KendoNumericTextBox Decimals="1" Format="#.0 days" Max="15" Min="0" Step="0.5m" Value="@employeeToUpdate.VacationDays" />
       }
   </EditorTemplate>
</TelerikGridColumn>

The column and editor templates give excellent control over column rendering in the grid. For even more control we can choose to use a row template and completely customize the grid.

Row Template

Unlike the previously mentioned templates, the RowTemplate spans the entire grid for all columns. The row template allows you to define custom rendering for the entire <tr> element for each record. It can be convenient if you want to use templates for most or all of the columns, as it requires less markup than setting individual templates for many columns.

Since the template isn't bound to a specific column, it can use the Context attribute of the RowTemplate to set the name of the context variable. Its type is the model type to which the grid is bound.

<RowTemplate Context="employee">
   <td>
       <span>@employee.Id</span>
   </td>
   <td>
       Hired on: @(String.Format("{0:dd MMM yyyy}", employee.HireDate))
   </td>
</RowTemplate>
<TelerikGridColumns>
   <TelerikGridColumn [email protected](SampleData.Name) Title="Employee Name" />
   <TelerikGridColumn [email protected](SampleData.HireDate) Title="Hire Date" />
</TelerikGridColumns>

Using the three template types we can tackle a wide variety of requirements. Let's look at how flexible the Telerik UI for Blazor Grid can be - what we can accomplish might just surprise you.

Image Template

We'll begin with a simple yet common scenario, embedding an image in a grid column. Let's assume we have a list of users that we need to manage a broad range of details for. It be nice to associate a face with a name, and with a column template we can do just that. Using a column template we can use one or many values from the currently bound item's properties to generate an image element and display an image directly in the column. In this example we'll assume that our product's images are stored on the server with a relative path of /images/, and each image file name corresponds to the productId.

Let's begin without a template to see how the grid is structured without customization.

<TelerikGrid [email protected] Height="500">
   <TelerikGridColumns>
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name"/>
       <TelerikGridColumn [email protected](Product.UnitPrice) Title="Unit Price"/>
   </TelerikGridColumns>
</TelerikGrid> 

@functions {
   public IEnumerable<Product> GridData { get; set; }
   
    protected override void OnInit() => GridData = ... //fetch data;
}

Here we have a basic two column grid with just a text display of each Product Name and Unit Price. Using a template we can transform the Product Name column to display an image alongside the product name.

To access the template, the Product Name column needs to have a TelerikGridColumn component with matching begin/end tags. Inside the component we'll add a Template component which will define our custom rendering. Inside of the template we have access to the context object, this is the current Product in scope. A simple cast of context as Product will give us access to the proper type.

<TelerikGridColumn [email protected](Product.ProductName) Title="Product Name">
   <Template>
       @{
           var product = context as Product;
       }
   </Template>
</TelerikGridColumn>

Now that we have our current Product we can render it how we see fit within the column. Let's add an HTML <img tag and create a path from the ProductId property. We can apply CSS to the image using standard HTML markup class="rounded-circle". Also, since this is Razor, C# string literals are a valid way of formating the path src="@($"/images/{product.ProductId}.jpg")". We'll also display the Product Name property along side the image using simple markup.

<TelerikGrid [email protected] Height="500">
   <TelerikGridColumns>
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name">
           <Template>
               @{
                   var product = context as Product;
                   <img class="rounded-circle" src="@($"/images/{product.ProductId}.jpg")" />
                   <span>@product.ProductName</span>
               }
           </Template>
       </TelerikGridColumn>
       <TelerikGridColumn [email protected](Product.UnitPrice) Title="Unit Price"/>
   </TelerikGridColumns>
</TelerikGrid>

@functions ...

Because the underlying Razor Components framework supports templates and the Telerik UI for Blazor Grid is built using the framework's native architecture, the grid is a fully capable solution to many problems.

Custom Form

With templates we can fully utilize Blazor's framework features. Inside the template we can add components, logic, and even trigger events. In addition, templates aren't just scoped to the component they're contained in - we can access events and values outside of the template as well. This opens up new possibilities for creating a custom experience.

Let's assume we want to create a custom edit experience versus using one of the built in grid editors. This will give us full control over every aspect of the form. The challenge is getting the form to interact with the grid. To make a custom editor we'll need to select an item, place its properties on a form, and save/cancel changes. On the surface this might seem like a complex task, however the framework has extremely flexible data binding mechanics.

Identifying the currently selected object would provide most of what we need to accomplish the task since we can bind its properties directly to form elements. The grid's template gives us access to items that are bound to a grid row, all we'll need is a method of selecting the value and creating a reference to the object. Let's start by creating a placeholder for our object reference using a field named selectedProduct. To create an easy way of selecting a product, a column template with a button will suffice. When the button is clicked, we'll invoke an in-line function to set selectedProduct to the current context.

<TelerikGridColumn [email protected](Product.ProductId) Title="Id">
   <Template>
       <TelerikButton Icon="edit" OnClick="@(=> selectedProduct = (Product)context)">Edit</TelerikButton>
   </Template>
</TelerikGridColumn>

With the data referenced we can now add a form to display the information and provide save and cancel actions. The form will exist outside of the grid, since the object reference is now scoped to the page we can place the form anywhere outside the grid. The form can be hidden or shown based on if an item is selected using a standard Razor @if block.

@if (selectedProduct != null) {
       ...form
}

Saving and canceling the edit are also straightforward tasks now. We just need to create buttons with corresponding OnClick events. To cancel the edit, the selectedProduct reference is simply reset to null.

<TelerikGrid [email protected] [email protected] Pageable="true" [email protected]>
   <TelerikGridColumns>
       <TelerikGridColumn [email protected](Product.ProductId) Title="Id">
           <Template>
               <TelerikButton Icon="edit" OnClick="@(=> selectedProduct = (Product)context)">Edit</TelerikButton>
           </Template>
       </TelerikGridColumn>
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name" />
       <TelerikGridColumn [email protected](Product.UnitPrice) Title="Unit Price" />
   </TelerikGridColumns>
</TelerikGrid>
<hr />
@if (selectedProduct != null)
{
   <div class="form-group ">
       <label class="control-label" for="productName">
           Product Name
       </label>
       <input class="form-control" bind="@selectedProduct.ProductName" id="name" name="name" type="text" />
   </div>
   <div class="form-group ">
       <label class="control-label" for="unitPrice">
           Unit Price
       </label>
       <input class="form-control" bind="@selectedProduct.UnitPrice" id="unitPrice" name="unitPrice" type="number" />
   </div>
   <div class="form-group">
       <div>
           <TelerikButton Icon="save" Class="k-primary" OnClick="@Save">Save</TelerikButton>
           <TelerikButton Icon="cancel" OnClick="@(_=> selectedProduct = null)">Cancel</TelerikButton>
       </div>
   </div>
}
@functions {
   ...
   Product selectedProduct;

   void Save()
   {
              // save logic
       selectedProduct = null;
   }
}

With the ability to share state with other components on the page, the opportunities for template driven experiences are unlimited.

Master-Detail View

Using templates we can completely transform an entire grid row with custom HTML, Razor, and even components. In this next example we'll look at just how advanced we can get with templates by adding a Master-Detail view to a grid.

A likely scenario for any application is one where a data point has many properties with varying importance. Some of those properties should always be front and center, while others might be helpful to have just within reach. This is where a master-detail view can be quite handy. This type of view helps keep extended data out of view until it is requested by the user, while keeping critical data up front all of the time.

Using the RowTemplate we can define two different states for our row which can easily be toggled by a simple button click. We'll start with the default state which only displays two columns of data. This view is nicely tucked away in a custom component called ProductMasterTemplate and takes a parameter of Product to be displayed in a two column format.

<ProductMasterTemplate Product="@product" />

HTML

In addition, we'll use a more complex view to reveal all of the data for a given product in a list view. Once again, we'll encapsulate the view in custom component called ProductDetailTemplate.

<ProductDetailTemplate Product="@product"/>

Within each of these custom components are table data cells <td> that contain Razor code for displaying the properties of a given Product. The contents of the row template must be <td> elements and their number (or total colspan) must match the number of columns defined in the grid. Internally both templates contain markup similar to the following example.

<td>@Product.property</td>
<td colspan="2">
       ... some view logic
</td>

With the two states clearly defined as components we can focus on switching between the two. Let's begin by defining which item is selected by creating a variable where we can hold a reference to the selected product. As such, we'll name it SelectedProduct. To enable the user to toggle between views, we'll need a set of buttons to display for the user. To show the details we'll simply check the SelectedProduct to see if it matches the current item in the row. Since we're using Blazor, we can easily set the state of SelectedProduct directly in the event handler with an in-line function, OnClick="@(=> SelectedProduct = ...)".

   <RowTemplate Context="product">
       @if (SelectedProduct != product)
       {
           <td>
               <TelerikButton Icon="@IconName.Window" OnClick="@(=> SelectedProduct = product)">Details</TelerikButton>
           </td>
           <ProductMasterTemplate Product="@product" />
       }
       else
       {
           <td>
               <TelerikButton  Icon="@IconName.Close" OnClick="@(=> SelectedProduct = null)">Close</TelerikButton>
           </td>
           <ProductDetailTemplate Product="@product"/>
       }
   </RowTemplate>

The completed code below is actually quite simple due to the combination of template and component architecture.

<TelerikGrid [email protected] Height="@Height">
   <RowTemplate Context="product">
       @if (SelectedProduct != product)
       {
           <td>
               <TelerikButton Icon="@IconName.Window" OnClick="@(=> SelectedProduct = product)">Details</TelerikButton>
           </td>
           <ProductMasterTemplate Product="@product" />
       }
       else
       {
           <td>
               <TelerikButton  Icon="@IconName.Close" OnClick="@(_=> SelectedProduct = null)">Close</TelerikButton>
           </td>
           <ProductDetailTemplate Product="@product"/>
       }
   </RowTemplate>
   <TelerikGridColumns>
       <TelerikGridColumn Width="100" [email protected](Product.ProductName) Title="Product" />
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name" />
       <TelerikGridColumn [email protected](Product.UnitsInStock) Title="Unit Price" />
   </TelerikGridColumns>
</TelerikGrid>

@functions {
   Product SelectedProduct;
}

Clicking the Details button gives us a slick UI that allows us to drill into grid data.

Conclusion

Because the Telerik UI for Blazor components are native, built from the ground up using the Blazor framework, it can tap directly in to Blazor's best features. Grid component templates can fully utilize the HTML, Razor, and components to completely customize the user experience. Simple templates are useful for formatting or displaying images, while more extensive templates can transform the user interface completely adding entirely new functionality to the grid.

In this post we focused on the grid, however other components like the DropDownList already feature template fields as well. Make sure you download the latest release and try the templates for yourself using our demo repository on GitHub.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading about Blazor

Blazor CRUD Using Google Cloud Firestore

Blazor: A new framework for browser-based .NET Apps

MVC.Net Web Application Development Services| MVC.Net Expertise | Hire MVC.Net Developers

CMARIX is among leading MVC.Net web application Development Services. We have the inhouse team of MVC.Net expertise to build scalable, standards-based MVC architecture enterprise applications as per your business needs.

CMARIX is among leading MVC.Net web application Development Services. We have the inhouse team of MVC.Net expertise to build scalable, standards-based MVC architecture enterprise applications as per your business needs.

The Life-Cycle of an ASP.NET Application In Web Development

If you are a beginner in ASP.NET, You Should understand the life-cycle of an ASP.NET Application In web development.

Whenever a user tries to access a particular page or when a page is requested by the user from the browser, the request goes through a series of steps and numerous processes run under the hood in the background, in order to produce the output or send the response back to the client. 

The time period and the processes that run between the request and response of a page is called the "Page Life Cycle".

Request:- Start of the life cycle (sent by the user).

Response:- End of the life cycle (sent by the server).

The application life cycle has the following stages to put them into brief:-

  • User makes a request for accessing application resource, a page. Browser sends this request to the web server.
  • A unified pipeline receives the first request and the following events take place:
  • An object of the class ApplicationManager is created.
  • An object of the class HostingEnvironment is created to provide information regarding the resources.
  • Top level items in the application are compiled.
  • Response objects are created. The application objects such as HttpContext, HttpRequest and HttpResponse are created and initialized.
  • An instance of the HttpApplication object is created and assigned to the request.
  • The request is processed by the HttpApplication

The life-cycle of an ASP.NET page

Whenever someone requests a page, it gets loaded into the server memory, processed, and sent back to the browser. It then gets unloaded from the memory. During each of these steps, methods and events are available, and there is a chance that it could be overridden according to the needs of the application. At the same time, one can write their own code to override the default code.

The Page class engineers a hierarchical tree of all the controls on the page. Every single component on the page, except the directives, becomes a part of this control tree. You can see the control tree by adding trace= "true" to the page directive.

What are the events that occur in ASP.NET page life-cycle

During each stage of the page life cycle, the page raises some events, which could be coded. Talking about event handler, it is a function or subroutine, bound to the event, using declarative attributes such as Onclick or handle.

PreInit - This is the first event in the page life cycle. It checks the IsPostBack property and establishes whether the page is a postback. It helps in setting up the themes and master pages, creates dynamic controls, and gets and sets profile property values. This particular event can be handled by overloading the OnPreInit method or creating a Page_PreInit handler.

Init - Init event kickstarts the control property and the control tree gets built. The event can be handled by overloading the OnInit method or creating a Page_Init handler.

InitComplete - InitComplete event enables tracking of view state. Each and every controls turn on view-state tracking.

LoadViewState - LoadViewState event allows loading view state information straight into the controls.

LoadPostData - At the time of this phase, the contents of all the input fields are defined with the <form> tag are processed.

PreLoad - The PreLoad event unfolds right before the postback data is loaded in the controls. This event can easily be handled by overloading the OnPreLoad method or creating a Page_PreLoad handler.

Load - This event is raised for the page first and after that, recursively for all the child controls. The controls in the control tree are created. One can handle this event by overloading the OnLoad method or creating a Page_Load handler.

Conclusion

ASP.NET has a long lasting future. Most of the web development today is done on ASP.NET pages. Today you can easily hire ASP.NET developers and start building your dream website today.

DevOps For ASP.NET Developers

DevOps is the union of people, process, and products to enable continuous delivery of value to our end users. Azure DevOps is everything you need to turn an idea into a working piece of software.


Abel and Jeremy introduce us the benefits of DevOps. They give us a high level overview of how to implement some DevOps best practices using Azure DevOps.

Abel and Jeremy explain the difference between these two options and show how we can get started with Azure Repos. They will walk us through creating branches, adding policies, and also integrating with GitHub.

Thanks for reading ❤

If you liked this post, share it with all of your programming buddies!

Follow me on Facebook | Twitter

Learn More

The Complete ASP.NET MVC 5 Course

Build a Real-world App with ASP.NET Core and Angular 2 (4+)

Build an app with ASPNET Core and Angular from scratch

Introduction to ASP.NET Core 2.2

Build a REST API with ASP.NET Core 2.2

Build amazing web apps with ASP.NET Core 3.0

Angular and .NET Core

Building Web App using ASP.NET Web API Angular 7 and SQL Server