The Grid performance worsens progressively with each subsequent edit operation. Please optimize that.
Test page: https://blazorrepl.telerik.com/mJuHFNbb17FpJu9b54
Click on a Price or Quantity cell to start edit mode and tab repetitively to observe the degradation.
I have a Telerik Pager within a Telerik Grid. If I select a larger page size within the pager, then select a smaller size and do not scroll, the next time I open the pager, the dropdown portion opens in the wrong place. When I view the inspect tool, it appears that the CSS top value is not being updated when changing page sizes from bigger to smaller. Is this a Telerik limitation with the pager?
In the images, we select items per page from 10 to 25, and then we go immediately from 25 to 10 items per page. Without scrolling, we click into the drop down list again and we are able to replicate this issue.
Before: Items per page: 10 -> 25
After:
Thank you in advance.
Currently, when a user exports the Grid to Excel/CSV/PDF, the export file is generated as a base64 string.
Please provide the file as a byte[] instead of a base64 string for better performance.
I AutoFit all columns in the Grid but would like to be able to reset their width to the initial value at a later point.
===
TELERIK EDIT: Here are two workarounds for two possible scenarios:
<TelerikButton ThemeColor="@ThemeConstants.Button.ThemeColor.Primary"
OnClick="@AutoFitColumns">AutoFit Columns</TelerikButton>
<TelerikButton ThemeColor="@ThemeConstants.Button.ThemeColor.Success"
OnClick="@ResetColumns">Reset Column Widths</TelerikButton>
<TelerikGrid @ref="@GridRef"
Data="@GridData"
Reorderable="true"
Resizable="true">
<GridColumns>
<GridColumn Field="@nameof(Product.Id)" />
<GridColumn Field="@nameof(Product.Name)" />
<GridColumn Field="@nameof(Product.Category)" />
<GridColumn Field="@nameof(Product.Stock)" />
<GridColumn Field="@nameof(Product.Discontinued)" />
</GridColumns>
</TelerikGrid>
@code {
private TelerikGrid<Product>? GridRef { get; set; }
private List<Product> GridData { get; set; } = new();
private async Task AutoFitColumns()
{
if (GridRef == null)
{
return;
}
await GridRef.AutoFitAllColumnsAsync();
}
private async Task ResetColumns()
{
if (GridRef == null)
{
return;
}
var gridState = GridRef.GetState();
foreach (var columnState in gridState.ColumnStates)
{
columnState.Width = "auto;";
}
gridState.TableWidth = $"99.9{DateTime.Now.Millisecond}%"; // Set something close to 100% instead of removing the value
await GridRef.SetStateAsync(gridState);
}
protected override void OnInitialized()
{
for (int i = 1; i <= 5; i++)
{
GridData.Add(new Product()
{
Id = i,
Name = $"Product {i}",
Category = $"Category {i % 4 + 1}",
Stock = Random.Shared.Next(0, 100),
Discontinued = i % 3 == 0
});
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Category { get; set; } = string.Empty;
public int Stock { get; set; }
public bool Discontinued { get; set; }
}
}
<TelerikGrid @ref="@GridRef"
Data="@GridData"
Reorderable="true"
Resizable="true"
Width="@GridWidth"
ShowColumnMenu="true"
OnStateChanged="@( (GridStateEventArgs<Product> args) => OnGridStateChanged(args) )">
<GridColumns>
<GridCheckboxColumn SelectAll="true" />
<GridColumn Field="@nameof(Product.Id)" />
<GridColumn Field="@nameof(Product.Name)" />
<GridColumn Field="@nameof(Product.Category)" />
<GridColumn Field="@nameof(Product.Stock)" />
<GridColumn Field="@nameof(Product.Discontinued)" />
</GridColumns>
</TelerikGrid>
@code {
private TelerikGrid<Product>? GridRef { get; set; }
private List<Product> GridData { get; set; } = new();
private string GridWidth => $"{GridIntWidth}px";
private int GridIntWidth = 1000; // A pixel Grid width is required for this scenario
private int GridMaxTableIntWidth => GridIntWidth - 17; // Assuming no horizontal scrolling
private async Task OnGridStateChanged(GridStateEventArgs<Product> args)
{
if (args.PropertyName == "ColumnStates" && Double.Parse(args.GridState.TableWidth.Replace("px", "")) < GridMaxTableIntWidth)
{
args.GridState.TableWidth = $"99.9{DateTime.Now.Millisecond}%"; // Set something close to 100% instead of removing the value
int lastVisibleColumnIndex = GetLastVisibleIndex(args.GridState.ColumnStates);
args.GridState.ColumnStates.First(x => x.Index == lastVisibleColumnIndex).Width = "auto";
await GridRef!.SetStateAsync(args.GridState);
}
}
private int GetLastVisibleIndex(ICollection<GridColumnState> columnStates)
{
int index = 0;
var visibleColumnStates = columnStates.Where(x => !x.Visible.HasValue || x.Visible.Value);
foreach (var columnState in visibleColumnStates)
{
index = Math.Max(index, columnState.Index);
}
return index;
}
protected override void OnInitialized()
{
for (int i = 1; i <= 5; i++)
{
GridData.Add(new Product()
{
Id = i,
Name = $"Product {i}",
Category = $"Category {i % 4 + 1}",
Stock = Random.Shared.Next(0, 100),
Discontinued = i % 3 == 0
});
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Category { get; set; } = string.Empty;
public int Stock { get; set; }
public bool Discontinued { get; set; }
}
}
I am resetting the Grid State by calling Grid.SetState(null). This doesn't reset ColumnState<T>.Locked boolean to false and the columns remain locked.
---
ADMIN EDIT
---
A possible workaround for the time being is to additionally loop through the ColumnStates collection of the State and set the Locked property to false for each column.
I use a custom filter row for the Grid where I have added a custom component holding the filter cell content. I am saving the Grid state upon change and restoring it on initialization.
I noticed that the custom filter component is initialized before the Grid state. As a result, there is an applied filter but the input in the custom filter component does not show it.
This behaviour was new since version 6.0.0. With 5.1.1 it doesn't appear.
I am using this sample to implement server-side grouping:
https://github.com/telerik/blazor-ui/tree/master/grid/datasourcerequest-on-server/WasmApp
Now I need Aggregate sum for the price in the GroupFooterTemplate. When I add aggregates, exceptions are thrown if a group footer uses the aggregate value, if not - the grid simply does not look grouped.
---
ADMIN EDIT
The issue stems from the inability of the System.Text.Json to deserialize interfaces - there are a couple of interfaces in the datasource request and data source result related to aggregates. Preliminary review indicates that perhaps some or all of them might be changed to, for example, Dictionary<string, object> from the current IDictionary<string, object>, or perhaps the framework might "learn" to deserialize interfaces.
----
Consider the following scenario:
In this case, the Grid should focus the last focused cell in step 1. Instead the Grid focuses the first header cell.
I have a Grid with row selection and column virtualization. After selecting all rows and zooming out my browser to 80% or less, the column virtualization stops working - data is not loaded in the cells on vertical scroll.
The scenario is:
In this case, the Grid should not try to create or clone an edit item on its own. Instead, it should rely on the returned instance from OnModelInit. However, the Grid first fires OnModelInit and then it still tries to clone or create an edit item, which causes an exception.
A possible workaround is to manage the whole edit process manually, similar to the example with ListView popup editing.
OnChange and OnBlur event for editors (TelerikTextBox, NumericTextBox, and others) is not fired in InCell edit mode with Tab key.
I previously raised an issue regarding the grid popup editor not linking the labels with the generated text inputs which was creating an issue with screenreaders. Since upgrading to version 7.1.0, I've seen that this issue has been fixed but in a way that breaks editor templates. Previously, the "for" attribute of the generated label was being set to the label text, but now everything is being set to a generated GUID.
This is fine for the generated fields since they can link the labels to the controls automatically (by setting the ID of the control to the GUID), but for templates, this means that we cannot link the generated label to the control since we cannot get access to the GUID in the template (as far as I know). Previously, when the "for" attribute on templates was the same as the label text, I could set the ID of the custom template control to the label text and the controls will be linked correctly.
===
ADMIN EDIT
===
For the time being, possible workarounds are:Hello,
Please consider a Grid feature that changes the component layout on mobile devices or narrow screens. The idea is to switch the column layout to a card layout or anything similar to this example: https://css-tricks.com/responsive-data-tables/
It is possible to implement a similar behavior with the Telerik Blazor Grid and MediaQuery components, but it requires reusing the column titles in the CSS code: https://blazorrepl.telerik.com/GnYPmHFR176Jg5Yg02
===
Telerik Blazor team: Everyone who is interested in this feature, please vote for it to help us prioritize. Also, share your opinion about which Grid features you strictly need in the "mobile" layout and which ones you are ready to sacrifice. Some features don't make sense in a card / listview layout anyway, but still, the mobile-friendly Grid may require completely different HTML markup and UX, so some features may need to be completely revamped.
Hello,