Telerik blogs
DotNetT Dark_870x220

The TelerikGrid in Telerik UI for Blazor is a powerful tool for displaying multiple rows of objects. However, sometimes a grid can't provide a complete interface to the data. When that happens, for the most extensible solution, you can provide the user with the ability to switch from a row to the view they want. By integrating the TelerikGrid and the TelerikTabStrip, you can let the user select the item they want from a grid in one tab and then switch to another tab that shows additional information.

The source code for this article is available on GitHub: TelerikBlazorUIComponents

Configuring Events in the TelerikGrid

The first step in this process is to give the user the ability to select a row in the TelerikGrid. As of this writing, there isn't a native way to select an item in the grid (though there will be), but there are a couple of options you can use, including defining a template that includes a select button. For this post, however, I've chosen to exploit the event architecture of the TelerikGrid.

To access the TelerikGrid's events, first add the <TelerikGridEvents> element to the grid's markup, like this (for more about the TelerikGrid [Ed Note: formerly KendoGrid] see my earlier post):

<TelerikGrid Data="@customers">
  <TelerikGridEvents>
    <!-- ... -->
  </TelerikGridEvents>
  <!-- rest of grid markup... -->
</TelerikGrid>

As I said, while there is no OnSelect event in the grid's events, there are multiple other events (including OnDelete, OnUpdate, OnCreate, and OnCancel). For example, I can convert the existing OnEdit event into a “select row” UI event by tying it to a method in my page's functions block. I've called the method DisplayDetail:

<TelerikGridEvents>
  <EventsManager OnEdit="@((args) => DisplayDetail(args))"> />
</TelerikGridEvents>

By using a lambda expression, I've actually gone to more trouble here than I need to. I like the lambda-based syntax because it makes explicit that the grid will pass an argument to my DisplayDetail method. However, I could have achieved the same goal with just OnEdit="DisplayDetail".

To give the user a tool for selecting a row, I then add a TelerikGridCommandColumn as the first column in my <TelerikGridColumns> element. Within that element, I can add multiple buttons to the column using the <TelerikGridCommandButton> element – for this case, I only need one button. The Command attribute on the button lets me tie the button to one of the events specified in the <TelerikGridEvents> element (obviously, in this example, I'm going to use the “Edit” event). In addition, the TelerikGridCommandButton has an Icon attribute that lets me specify an icon to display in the button; I can also provide some text between the element's open and close tags to display as the button's caption. In this case, I stayed with the default edit icon and changed the caption text to “Select”:

<TelerikGridColumns>
  <TelerikGridCommandColumn>
    <TelerikGridCommandButton Command="Edit" Icon="edit">
      Select
    </TelerikGridCommandButton>
  </TelerikGridCommandColumn>
  <TelerikGridColumn Field="Id" Title="Customer Id" />
  <!-- more columns -->
</TelerikGridColumns>

Processing the Event

Now I need to write the method that will catch and process the event. I called my event DisplayDetail and I need to have it accept the GridCommandEventArgs object that the grid will pass to it. The skeleton for that method looks like this:

@functions
{  
  public void DisplayDetail(GridCommandEventArgs e)
  {
    // ...
  }

  // ...
}

The GridCommandEventArgs object has an Item property that points to the object displayed in the row that the user selected. Since my grid is displaying Customer objects, I can cast that Item property to a Customer object. I'll put that Customer object into a field to use in other parts of my UI:

private Customer currentCustomer;
public void DisplayDetail(GridCommandEventArgs e)
{
  currentCustomer = (Customer) e.Item;
}

By default, the grid is also going to put the row I selected into an edit mode. To prevent that from happening, I set GridCommandEventArgs.IsCancelled to true, which prevents the selected row's display from changing. At this point, then, my DisplayDetail method looks like this:

public void DisplayDetail(GridCommandEventArgs e)
{
  currentCustomer = (Customer) e.Item;
  e.IsCancelled = true;
}

My next step is to display the information from the row in a form rather than as a row in a grid. To handle that, I'm going to take advantage of the TelerikTabStrip.

Configuring Tabs

What I'm going to do is set up two tabs within the TelerikTabStrip: one tab to display the grid, and one to display the data from the selected row.

Moving my grid into a tab is easy: I just wrap my grid's markup inside a <TelerikTab> element inside a TelerikTabStrip. I'll use the TelerikTabStrip's TabPosition attribute to have the tabs display across the top of my page. I'll also add a second tab to display the individual customer. With both tabs, I'll use their Title attribute to set the text displayed in at the top of the tab:

<TelerikTabStrip ref="@tabstrip" TabPosition="TelerikTabPosition.Top">
  <TelerikTab ref="@currenttab" Title="Customer List">
    <TelerikGrid Data="@customers">
      <!-- grid markup -->
    </TelerikGrid>
  </TelerikTab>
  <TelerikTab Title="Current Customer">
    <!-- markup to display the selected customer -->
  </TelerikTab>
</TelerikTabStrip>

Initially, I want the “Current Customer” tab to be disabled and enabled only after a customer is selected. To handle enabling/disabling the tabs, I'll need to bind the tab's Disabled attribute to some field or property I can set from code. I'll call this field currentCustomerTabDisable:

private bool currentCustomerTabDisable = true;

Now, in my DisplayDetail method's code, after retrieving the selected Customer, I set the field to false:

public void DisplayDetail(GridCommandEventArgs e)
{
  Customer cust = (Customer) e.Item;
  e.IsCancelled = true;
  currentCustomerTabDisable = false;
  StateHasChanged();
}

Of course, this won't do any good unless I also tie the Disabled attribute on my tab to the field. That markup looks like this:

<TelerikTab Title="Full Customer"
          Disabled="@currentCustomerTabDisable">
  <!-- ... -->
</TelerikTab>

Displaying the Selected Customer

Having gone to all that trouble, the final step is to display the selected Customer's information in the second tab. That's “plain old Blazor code”: I add some textboxes to the second tab and use the bind attribute to associate the textbox with my currentCustomer field. That markup looks like this:

<TelerikTab Title="Full Customer"
          Disabled="@currentCustomerTabDisable">
  <input type="text" bind="@currentCustomer.FirstName" />
  <input type="text" bind="@currentCustomer.LastName" />
</TelerikTab>

Because the bind attribute implements two-way databinding, changes made on the “current customer tab” are automatically reflected in the grid.

Of course, if I was a decent human being, I wouldn't just enable the “current customer tab”, I would also switch the user to that tab. I can do that by calling the SetActiveTab method, passing a reference to the tab I want to display. However, to access the tabstrip (so that I can call its SetActiveTab method) and the tab (so I can pass it to the SetActiveTab method), I first need references to both. That's a three-step process.

First, I add the ref attribute to the <TelerikTabStrip>, tying it to a field in my function's block called I've called “tabStrip”:

<TelerikTabStrip ref="@tabStrip" TabPosition="TelerikTabPosition.Top">
  <!-- ... -->
</TelerikTabStrip>

In the same way, this markup ties the tab to a field called currentCustomerTab:

<TelerikTab ref="@currentCustomerTab"
          Title="Full Customer"
          Disabled="@currentCustomerTabDisable">
  <!-- ... -->
</TelerikTab>

The second step is to add those fields to my functions block. A TelerikTab implements the ITab interface, which suggests that there may be multiple kinds of tabs in the future. To support that possibility, I declare my currentCustomerTab as an ITab:

@functions {
  private TelerikTabStrip tabStrip;
  private ITab currentCustomerTab;
  // ...
}

With those references to the TelerikTabStrip and TelerikTab in place, I can update my DisplayDetail method to switch the user to the second tab:

public void DisplayDetail(GridCommandEventArgs e)
{
  currentCustomer = (Customer) e.Item;
  e.IsCancelled = true;
  currentCustomerTabDisable = false;
  tabStrip.SetActiveTab(currentCustomerTab);
  StateHasChanged();
}

One of the nice features of this design is that it's almost infinitely extensible: As you add more customer-related functionality to this page, you can just keep adding more tabs. And all it will cost you is some markup and about half a dozen lines of code.


Peter Vogel
About the Author

Peter Vogel

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter also writes courses and teaches for Learning Tree International.

Related Posts

Comments

Comments are disabled in preview mode.