DataGrid: Templates
Templates
For extra customization DataGrid
will provide you with two additional templates that you can use to extend it’s default behavior.
A display template is used to customize display cells and an edit template is used to customize cell editors. You can place anything inside of the templates, be it a Blazorise components, regular html tags or your own components.
Both templates have a special context
attribute that is used to give access to the underline cell value. To learn more about context
please go to official Blazor documentation.
DisplayTemplate
Display template is usingTItem
as a context value.
<DataGrid TItem="Employee" Data="" Responsive> <DataGridNumericColumn Field="@nameof(Employee.DateOfBirth)" Caption="Date Of Birth" Editable> <DisplayTemplate> @{ var date = ( context as Employee )?.DateOfBirth; if ( date != null ) { @($"{date.Value.ToShortDateString()} | Age: {( DateTime.Now.Year - date.Value.Year )}") } } </DisplayTemplate> </DataGridNumericColumn> </DataGrid>
@code{ [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
EditTemplate
Edit template will give you a way to handle the editing of grid cell values. For this templateCellEditContext
is used as a context
value. Use it to get or set the cell values.
<DataGrid TItem="Employee" Data="" Editable Responsive> <DataGridCommandColumn /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGrid>
@code{ [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
DetailRowTemplate
DetailRowTemplate
allows you to display nested structure bellow each row in the grid. One of the examples is “master-detail” relationship between two data-source inside the DataGrid
.
For this template the context
value is the item from the parent grid.
Once it’s defined a detail-row will be visible for every row in the grid by default. You may change this behaviour by setting DetailRowStartsVisible
to false.
If you want to control the visibility of detail-row you can use DetailRowTrigger
attribute that can be defined in it’s parent grid.
Once defined, whenever a user clicks a row, the DetailRowTrigger
will be evaluated. You may also use the DataGrid API, ToggleDetailRow
to programatically trigger the detail-row.
<DataGrid TItem="Employee" Data="" @bind-SelectedRow="" DetailRowTrigger="@((e) => e.Item.Salaries?.Count > 0 && e.Item.Id == selectedEmployee?.Id)" Responsive> <DataGridColumns> <DataGridCommandColumn /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" /> </DataGridColumns> <DetailRowTemplate> @{ var salaries = ( context as Employee ).Salaries; <DataGrid TItem="Salary" Data="salaries" Sortable="false" ShowCaptions="false"> <DataGridCommandColumn /> <DataGridDateColumn Field="@nameof(Salary.Date)" Caption="Date" /> <DataGridNumericColumn Field="@nameof(Salary.Total)" Caption="Total" /> </DataGrid> } </DetailRowTemplate> </DataGrid>
@code{ [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
Command Templates
If you want to change the default command buttons, you can use following templates:
NewCommandTemplate
EditCommandTemplate
SaveCommandTemplate
CancelCommandTemplate
DeleteCommandTemplate
ClearFilterCommandTemplate
<DataGrid TItem="Employee" Data="" @bind-SelectedRow="" Editable Responsive> <DataGridCommandColumn> <NewCommandTemplate> <Button Color="Color.Success" Clicked="@context.Clicked">New</Button> </NewCommandTemplate> <EditCommandTemplate> <Button Color="Color.Primary" Clicked="@context.Clicked">Edit</Button> </EditCommandTemplate> </DataGridCommandColumn> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGrid>
@code{ [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }
Loading Templates
If you want to change display of content, while grid is empty or ReadData
is executing, you can use following templates:
EmptyTemplate
LoadingTemplate
<DataGrid @ref="datagridRef" TItem="Employee" Data="" @bind-SelectedRow="" TotalItems="" ReadData="" Responsive> <DataGridColumns> <DataGridCommandColumn /> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGridColumns> <EmptyTemplate> <div class="box"> No employees were found! </div> </EmptyTemplate> <LoadingTemplate> <Progress @ref="progressRef" Color="Color.Primary" Max="100" Value="progress" /> </LoadingTemplate> </DataGrid> <Button Background="Background.Primary" Color="Color.Light" Clicked="() => datagridRef.Reload()">Load</Button>
@code{ protected DataGrid.DataGrid<Employee> datagridRef; protected Progress progressRef; protected int progress; protected Employee selectedEmployee; protected int totalEmployees = 0; protected List<Employee> employeeList; public async Task LoadEmployeesFromService( DataGridReadDataEventArgs<Employee> e ) { /* * This can be call to anything like calling an api to load employees. * During execution 'LoadingTemplate' will be displayed. * If your api call returns empty result, then 'EmptyTemplate' will be displayed, * this way you have proper feedback, for when your datagrid is loading or empty. */ progress = 0; await InvokeAsync( StateHasChanged ); await Task.Delay( 500 ); progress = 25; await InvokeAsync( StateHasChanged ); await Task.Delay( 500 ); progress = 50; await InvokeAsync( StateHasChanged ); await Task.Delay( 500 ); progress = 75; await InvokeAsync( StateHasChanged ); await Task.Delay( 500 ); progress = 100; await InvokeAsync( StateHasChanged ); } }
ButtonRow Template
Provide a ButtonRowTemplate
and have the DataGridCommandMode
set to either Default
or ButtonRow
.
The template has access to the internal commands so you’re also able to construct your own buttons on the pager that can also trigger the Datagrid’s CRUD and clear filter operations as shown in the example below:
DataGridEditMode
is set to Inline
, you should take note that if you'd like to customize the Save/Cancel buttons, you should do so by using the DataGridCommandColumn
as the Save/Cancel buttons are configured/rendered in this column.ButtonRowTemplate
is located inside the Datagrid's Pager
, as such the ShowPager
Parameter should be set to true.<DataGrid TItem="Employee" Data="" @bind-SelectedRow="" Editable Responsive ShowPager CommandMode="DataGridCommandMode.ButtonRow"> <DataGridColumns> <DataGridColumn Field="@nameof(Employee.Id)" Caption="#" Sortable="false" /> <DataGridColumn Field="@nameof(Employee.FirstName)" Caption="First Name" Editable /> <DataGridColumn Field="@nameof(Employee.LastName)" Caption="Last Name" Editable /> <DataGridColumn Field="@nameof(Employee.Email)" Caption="Email" Editable /> <DataGridColumn Field="@nameof(Employee.Salary)" Caption="Salary" DisplayFormat="{0:C}" DisplayFormatProvider="@System.Globalization.CultureInfo.GetCultureInfo("fr-FR")" Editable> <EditTemplate> <NumericEdit TValue="decimal" Value="@((decimal)context.CellValue)" ValueChanged="@( v => context.CellValue = v)" /> </EditTemplate> </DataGridColumn> </DataGridColumns> <ButtonRowTemplate> <Button Color="Color.Success" Clicked="context.NewCommand.Clicked">New</Button> <Button Color="Color.Primary" Disabled="(selectedEmployee is null)" Clicked="context.EditCommand.Clicked">Edit</Button> <Button Color="Color.Danger" Disabled="(selectedEmployee is null)" Clicked="context.DeleteCommand.Clicked">Delete</Button> </ButtonRowTemplate> </DataGrid>
@code{ [Inject] public EmployeeData EmployeeData { get; set; } private List<Employee> employeeList; private Employee selectedEmployee; protected override async Task OnInitializedAsync() { employeeList = await EmployeeData.GetDataAsync(); await base.OnInitializedAsync(); } }