If a developer changes the structure of the grid in a new release, such as adding or removing columns, the restore can have very unexpected results.
We get around this by storing a version number with the grid and incrementing that number when we change the grid columns. If the version number on the grid does not match the version number stored with the state, we don't restore it.
We would like to see this be more of an automatic feature of the grid.
Compare the columns in the saved state with the columns in the Grid declaration. You may need to change the way the Grid columns are declared, according to the the linked documentation. If there is inconsistency between the two collections, strip the column information from the saved state before restoring it. (This was suggested by Dimo from Telerik in a support ticket)
An alternative would just be to throw away that state when it can't be safely restored.
How can I get the tooltips for validation of each field displayed at the corresponding field in a Grid Popup form, not just the summary below the Form, etc?
---
ADMIN EDIT
---
This will be handled through exposing an option to set your preferred field validation message type - tooltip or inline. It will cover all edit modes (Popup, Inline, InCell).
If you want to remove the ValidationSummary after adding field validation messages, check the ability to remove ValidationSummary from the Popup edit form.
Here is a runnable REPL test page. A possible workaround is to render the Grid only if it has columns:
@{
if (GridColumns.Count() > 0)
{
<TelerikGrid Data="@Data">
<GridColumns>
@foreach (var column in GridColumns)
{
<GridColumn Field="@column.DataField"
ShowColumnMenu="false" Title="@column.DisplayName" Resizable="true" Width="500px">
<FooterTemplate>
foo
</FooterTemplate>
</GridColumn>
}
</GridColumns>
</TelerikGrid>
}
}
Hello,
When a Grid is using multi column headers, and I add one more column in the OnBeforeExport event, this new column has no title in the exported file.
A possible workaround might be to use a column with zero Width and change the width in OnBeforeExport.
@using Telerik.Blazor.Common.Export.Excel
@using Telerik.Blazor.Components.Grid
<TelerikGrid TItem="@FlowRun"
Pageable="true"
OnRead="@GetData">
<GridToolBar>
<GridCommandButton Command="ExcelExport" Icon="file-excel">Export to Excel</GridCommandButton>
<GridCommandButton Command="CsvExport" Icon="file-csv">Export to CSV</GridCommandButton>
<label class="k-checkbox-label"><TelerikCheckBox @bind-Value="@ExportAllPages" />Export All Pages</label>
</GridToolBar>
<GridExport>
<GridExcelExport FileName="telerik-grid-export" AllPages="@ExportAllPages" OnBeforeExport="@BeforeExcelExport" />
<GridCsvExport FileName="telerik-grid-export" AllPages="@ExportAllPages" OnBeforeExport="@BeforeCsvExport" />
</GridExport>
<GridColumns>
<GridColumn Field="@nameof(FlowRun.FileName)" Title="File Name" Width="300px" />
<GridColumn Field="@nameof(FlowRun.Type)" Title="Type" Width="100px" />
<GridColumn Field="@nameof(FlowRun.FileSize)" Title="File Size" Width="200px" />
<GridColumn Title="Source">
<Columns>
<GridColumn Field="@(nameof(FlowRun.Source))" Title="MPID"/>
<GridColumn Field="@(nameof(FlowRun.SourceFileProtocol))" Title="Type" />
</Columns>
</GridColumn>
<GridColumn Field="@nameof(FlowRun.ErrorMessage)"
Title = "Error"
Width="0" />
</GridColumns>
</TelerikGrid>
@code {
bool ExportAllPages { get; set; }
private async Task GetData(GridReadEventArgs args)
{
args.Data = Enumerable.Range(1, 10).Select(x => new FlowRun
{
FileName = $"File {x}",
Type = $"Type {x}",
FileSize = x * 2,
Source = $"Source {x}",
SourceFileProtocol = FileProtocol.CIX,
ErrorMessage = $"Error {x}"
}).ToList();
args.Total = 100;
}
private void BeforeCsvExport(GridBeforeCsvExportEventArgs obj)
{
AddErrorMessageColumn(obj);
}
private void BeforeExcelExport(GridBeforeExcelExportEventArgs obj)
{
AddErrorMessageColumn(obj);
}
private void AddErrorMessageColumn(GridBeforeSpreadsheetExportEventArgs args)
{
args.Columns.Find(x => x.Field == nameof(FlowRun.ErrorMessage)).Width = "100px";
//args.Columns.Add(new ExcelExportableColumn
//{
// Field = nameof(FlowRun.ErrorMessage),
// Title = "Error"
//});
}
public class FlowRun
{
public string FileName { get; set; }
public string Type { get; set; }
public long? FileSize { get; set; }
public string Source { get; set; }
public FileProtocol SourceFileProtocol { get; set; }
public string ErrorMessage { get; set; }
}
public enum FileProtocol
{
Unknown,
PIX,
CIX,
SS
}
}
Hello,
The filter row noticeably slows down the tabbing speed during Grid in-cell editing in WASM apps.
Triggering Edit in a Grid bound to a DataTable or ExpandoObject and with edit mode set to Popup throws an unhandled exception. This started to occur in 4.1.0 - the same code runs fine on 4.0.1
To reproduce:
Hello,
new version has broken "dynamic" changing column properties/visiblity runtime, especially- selection mode and causing lot of "rerendering".
Video attachment:
1 - first part is OLD version(prior 4.1.0) 4.0.1
2 - seccond part(after changing next browser tab) is new version 4.1.0
SAME setup
Iam already using hint for blazor with IDs of columns, found in Your documentation...etc. @key="@("sIDX")"
.....
-->>Clicking on Button for changing grid mode and visibility of columns**
<TelerikToggleButton Title="Oznaceni vice radku" Icon="@FontIcon.ListUnordered" OnClick="@( _ =>{ CurrentStackItem.gSelectionMode=(CurrentStackItem.gSelectionMode==GridSelectionMode.Multiple)?GridSelectionMode.Single:GridSelectionMode.Multiple;CurrentStackItem.gSelectedItems = Enumerable.Empty<ExpandoObject>();})"
Selected="@(CurrentStackItem.gSelectionMode==GridSelectionMode.Multiple)"></TelerikToggleButton>
....
<GridColumns>
-->>First "static" 2 columns**
<GridCheckboxColumn Visible=@(CurrentStackItem.gSelectionMode==GridSelectionMode.Multiple) @key="@("sIDX")" Width="70px" Locked="true" SelectAll="true" SelectAllMode="GridSelectAllMode.Current"></GridCheckboxColumn><GridColumn FieldType=@typeof(bool) Visible=@(IsPicker==true || (XSmall==false && CurrentStackItem.gSelectionMode==GridSelectionMode.Single )) @key="@("sCMD")" Filterable="false" Sortable="false" Locked="true" Width="@((IsPicker==true && XSmall==true)?"45px":"120px")">
<HeaderTemplate> </HeaderTemplate><Template Context="ctx"><div @onclick:preventDefault="true" @onclick:stopPropagation="true">
-->> THIS part is hitting LOT OF TIME in debug (expected is at best only once)
@{if (XSmall==false)
{
-->> here is LOT OF dynamic buttons.
}
</div></Template></GridColumn>
-->> rest of the dynamic columns. In video, starting with "ciiislo org" in header
@if (GridDef.ColStore != null && GridDef.ColStore.Any())
{
foreach (var it in GridDef.ColStore.Where(x => x.Verejny == true))
{
<GridColumn @key=@it.FldName Field=@it.FldName FieldType=@it.FldType Title=@it.VerejnyNazev ShowFilterCellButtons="false" Width=@it.cSirkaSestava
TextAlign=@it.cZarovnani
><FooterTemplate>
@if (it.Sumovat == true)
{
@context.Sum
}
</FooterTemplate></GridColumn>
}
}
</GridColumns>
Feel free to change the Subject.
Thanks, have a nice day
I want to filter a Grid by DateTimeOffset? field
===ADMIN EDIT===
There are two possible options:
1. Use a DTO in which you have a DateTime field converted as desired by your app from the DateTimeOffset. Filtering, sorting, editing, and grouping on DateTime values are supported out-of-the-box.
REPL example that demonstrates this approach.
2. Use the Grid Filter Template. As a filter editor, you can use the DateTimePicker component, which supports the DateTimeOffset type.
REPL example that demonstrates this approach.
Problem Statement:
We have the following blazor grid:
We have enabled the GridColumnMenuSettings
Now when we open the column chooser it does not disable for the last option.
When we don't have the GridCheckboxColumn then it works as intended
The last column option is disabled
Expected Result : We don't want the check box column to be shown in the column chooser and the last option to be unchecked in the column chooser needs to be disabled.
@* Use the Template to render the list of columns and add some custom styles *@
<TelerikGrid Data="@MyData"
Pageable="true"
PageSize="5"
Width="700px"
FilterMode="@GridFilterMode.FilterMenu"
Sortable="true"
ShowColumnMenu="true">
<GridSettings>
<GridColumnMenuSettings Sortable="true"
Lockable="false"
FilterMode="@ColumnMenuFilterMode.None" />
</GridSettings>
<GridColumns>
<GridCheckboxColumn Width="80px" HeaderClass="header-select-all" />
<GridColumn Field="@(nameof(SampleData.Id))" Width="80px" Title="Id" Id="id-column-id" />
<GridColumn Field="@(nameof(SampleData.FirstName))" Title="First Name" Id="firstname-column-id" />
<GridColumn Field="@(nameof(SampleData.LastName))" Title="Last Name" Id="lastname-column-id" />
<GridColumn Field="@(nameof(SampleData.CompanyName))" Title="Company" Id="companyname-column-id" />
<GridColumn Field="@(nameof(SampleData.Team))" Title="Team" Id="team-column-id" />
<GridColumn Field="@(nameof(SampleData.HireDate))" Title="Hire Date" Id="hiredate-column-id" />
</GridColumns>
</TelerikGrid>
@code {
public string TextboxValue { get; set; } = string.Empty;
public IEnumerable<SampleData> MyData = Enumerable.Range(1, 30).Select(x => new SampleData
{
Id = x,
FirstName = $"FirstName {x}",
LastName = $"LastName {x}",
CompanyName = $"Company {x}",
Team = "team " + x % 5,
HireDate = DateTime.Now.AddDays(-x).Date
});
public class SampleData
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string CompanyName { get; set; }
public string Team { get; set; }
public DateTime HireDate { get; set; }
}
}
When I click TelerikGridCommandButton and inside OnClick event calling method uriHelper.NavigateTo("/xxx"); application hangs.
Using latest VS 2019 version and Blazor Preview 4
I'm following your example listed here (in ObservableCollection section)
https://docs.telerik.com/blazor-ui/components/grid/selection/overview
The following scenario does not work.
Select an item in the grid.
Clear data set. Grid (simplified) look like this. Notice that the checkbox is selected even though nothing is in the grid.
Uncheck chekcbox.
Check checkbox -> All items from the previous data set will be selected (printed in ul bellow grid)
I have inspected the grid and i does not contain any item in its Data collection so I'm unsure from where does it get the selection.
Best regards,
Robert
When I set more than one group on StateInit, I get an error - either the browser closes, or I see a stack overflow.
Sample reproducible with workaround (to initialize the data source so it is not null) is below
Sample error and stack trace
ArgumentNullException: Value cannot be null. (Parameter 'source')
<TelerikGrid Data=@GridData Pageable="true" Height="300px">
<GridColumns>
<GridColumn Field="@(nameof(Employee.EmployeeId))">
<FooterTemplate>
some footer
</FooterTemplate>
</GridColumn>
<GridColumn Field=@nameof(Employee.Salary) Title="Salary">
</GridColumn>
<GridColumn Field=@nameof(Employee.Name)>
</GridColumn>
</GridColumns>
</TelerikGrid>
@code {
public List<Employee> GridData { get; set; } // = new List<Employee>(); // workaround
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public decimal Salary { get; set; }
}
}
I am trying to get the currently filtered data out of the grid as per this KB article and I want to include the searchbox filters. I do not, however, want to use OnRead but I want to get the grid state on a click of a button and get the filters plus the searchbox filters from it instead.
---
ADMIN EDIT
Here is a sample of getting those filters through the OnRead event without using remote operations - all the data is in the view model (the SourceData field) so this does not change the way operations happen compared to not using OnRead.
@using Telerik.DataSource
@using Telerik.DataSource.Extensions
@( new MarkupString(output) )
<br />
<TelerikButton OnClick="@GetFilters">Get Filters</TelerikButton>
<TelerikGrid Data=@GridData TotalCount=@Total OnRead=@ReadItems
FilterMode=@GridFilterMode.FilterRow Sortable=true Pageable=true EditMode="@GridEditMode.Inline">
<GridToolBar>
<GridSearchBox />
</GridToolBar>
<GridColumns>
<GridColumn Field=@nameof(Employee.ID) />
<GridColumn Field=@nameof(Employee.Name) Title="Name" />
<GridColumn Field=@nameof(Employee.HireDate) Title="Hire Date" />
<GridCommandColumn>
<GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</GridCommandButton>
<GridCommandButton Command="Edit" Icon="edit">Edit</GridCommandButton>
<GridCommandButton Command="Delete" Icon="delete">Delete</GridCommandButton>
<GridCommandButton Command="Cancel" Icon="cancel" ShowInEdit="true">Cancel</GridCommandButton>
</GridCommandColumn>
</GridColumns>
</TelerikGrid>
@code {
TelerikGrid<Employee> GridRef { get; set; }
string output { get; set; }
public DataSourceRequest CurrentRequest { get; set; }
void GetFilters()
{
output = string.Empty;
foreach (var item in CurrentRequest.Filters)
{
if (item is FilterDescriptor) // filter row
{
FilterDescriptor currFilter = item as FilterDescriptor;
output += $"field: {currFilter.Member}, operator {currFilter.Operator}, value: {currFilter.Value}<br />";
}
if (item is CompositeFilterDescriptor) // filter menu
{
CompositeFilterDescriptor currFilter = item as CompositeFilterDescriptor;
output += $"START nested filter: logical operator: {currFilter.LogicalOperator}, details:<br />";
// there will actually be 1 or 2 only, this showcases the concept and the types
foreach (FilterDescriptor nestedFilter in currFilter.FilterDescriptors)
{
output += $"field: {nestedFilter.Member}, operator {nestedFilter.Operator}, value: {nestedFilter.Value}<br />";
}
output += "END nested filter<br />";
}
}
}
public List<Employee> SourceData { get; set; }
public List<Employee> GridData { get; set; }
public int Total { get; set; } = 0;
protected override void OnInitialized()
{
SourceData = GenerateData();
}
protected async Task ReadItems(GridReadEventArgs args)
{
CurrentRequest = args.Request;
var datasourceResult = SourceData.ToDataSourceResult(args.Request);
GridData = (datasourceResult.Data as IEnumerable<Employee>).ToList();
Total = datasourceResult.Total;
StateHasChanged();
}
//This sample implements only reading of the data. To add the rest of the CRUD operations see
//https://docs.telerik.com/blazor-ui/components/grid/editing/overview
private List<Employee> GenerateData()
{
var result = new List<Employee>();
var rand = new Random();
for (int i = 0; i < 100; i++)
{
result.Add(new Employee()
{
ID = i,
Name = "Name " + i,
HireDate = DateTime.Now.Date.AddDays(rand.Next(-20, 20))
});
}
return result;
}
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime HireDate { get; set; }
}
}
---
Hi Telerik team,
In a Blazor Grid with filters enabled the event "OnStateChanged" is fired twice when I use a filter (set, change, remove).
---
ADMIN EDIT
This behavior is expected - when the grid is filtered, there are two actions that happen:
This is not something we intend to change at this point.
---
To reproduce this I took one of the provided examples and added the event handler:
@page "/"
<TelerikGrid Data=@GridData
SelectionMode="GridSelectionMode.Multiple"
SelectedItemsChanged="@((IEnumerable<Employee> employeeList) => OnSelect(employeeList))"
SelectedItems="@PersistedSelectedItems"
@bind-Page="@CurrentPage"
PageSize="@PageSize"
Pageable="true"
FilterMode="GridFilterMode.FilterRow"
OnStateChanged="@((GridStateEventArgs<Employee> args) => OnStateChangedHandler(args))">
<GridColumns>
<GridCheckboxColumn />
<GridColumn Field=@nameof(Employee.EmployeeId) />
<GridColumn Field=@nameof(Employee.Name) />
<GridColumn Field=@nameof(Employee.Team) />
</GridColumns>
</TelerikGrid>
@if (PersistedSelectedItems != null)
{
<ul>
@foreach (Employee employee in PersistedSelectedItems.OrderBy(e => e.EmployeeId))
{
<li>
@employee.EmployeeId
</li>
}
</ul>
}
@code {
public List<Employee> PersistedSelectedItems { get; set; } = new List<Employee>();
int CurrentPage { get; set; }
int PageSize { get; set; } = 5;
private async void OnStateChangedHandler(GridStateEventArgs<Employee> args)
{
await Task.Delay(5000);
}
protected void OnSelect(IEnumerable<Employee> employees)
{
IEnumerable<Employee> CurrentPageEmployees = GridData.Skip(PageSize * (CurrentPage - 1)).Take(PageSize);
if (employees == null || employees.Count() == 0)
{
//the user de-selected all items with the header checkbox
PersistedSelectedItems = PersistedSelectedItems.Except(CurrentPageEmployees).ToList();
}
else
{
//handle any deselected items
var UnselectedEmployees = CurrentPageEmployees.Except(employees);
PersistedSelectedItems = PersistedSelectedItems.Except(UnselectedEmployees).ToList();
//add any new items if they were not selected already
foreach (var item in employees)
{
if (!PersistedSelectedItems.Contains(item))
{
PersistedSelectedItems.Add(item);
}
}
}
}
//data binding and sample data
public List<Employee> GridData { get; set; }
protected override void OnInitialized()
{
GridData = new List<Employee>();
for (int i = 0; i < 15; i++)
{
GridData.Add(new Employee()
{
EmployeeId = i,
Name = "Employee " + i.ToString(),
Team = "Team " + i % 3
});
}
}
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Team { get; set; }
}
}
Best regards,
Rayko