In the following reproducible, try filtering the third column (SomeNavigationProperty.Field1). It does not work.
<TelerikGrid Data="@myData" Pageable="true" Sortable="true" FilterMode="@GridFilterMode.FilterRow" Groupable="true">row height set in grid definition must apply to all rows in the grid for row virtualization as of now.
in real business case there might be complex content in each row that can't reinforce this - but if each row report its own height, grid still can visualize the load, and it will be much more flexible.
When I have a Navigable grid and I press Esc on the keyboard while editing/inserting a row, I want to do something (e.g., clean up the newly inserted row altogether from the data). Usually, I can use the OnCancel event for this, but it does not fire when pressing the Esc key on the keyboard.
*** Thread created on customer behalf by admin ***
When I enter edit mode for a cell (I used InCell edit mode), the row height decreases.
*** Thread created by admin on customer behalf ***
Select one or more rows
Right click another of the rows (there is code in the OnContextMenu handler that changes the selected items to the currently clicked row)
<TelerikContextMenu @ref="@ContextMenuRef" Data="@MenuItems" OnClick="@((MenuItem item) => OnItemClick(item))"></TelerikContextMenu>
<TelerikGrid Data=@GridData
@ref="Grid"
SelectionMode="GridSelectionMode.Multiple"
@bind-SelectedItems="@SelectedEmployees"
@bind-Page="@CurrentPage"
PageSize="@PageSize"
OnRowContextMenu="OnContextMenu"
Pageable="true">
<GridColumns>
<GridCheckboxColumn />
<GridColumn Field=@nameof(Employee.EmployeeId) />
<GridColumn Field=@nameof(Employee.Name) />
<GridColumn Field=@nameof(Employee.Team) />
</GridColumns>
</TelerikGrid>
@if (SelectedEmployees != null)
{
<ul>
@foreach (Employee employee in SelectedEmployees.OrderBy(e => e.EmployeeId))
{
<li>
@employee.EmployeeId
</li>
}
</ul>}
@code {
public IEnumerable<Employee> SelectedEmployees { get; set; } = Enumerable.Empty<Employee>();
TelerikContextMenu<MenuItem> ContextMenuRef { get; set; }
TelerikGrid<Employee> Grid { get; set; }
List<MenuItem> MenuItems { get; set; }
int CurrentPage { get; set; } = 1;
int PageSize { get; set; } = 5;
//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
});
}
MenuItems = new List<MenuItem>()
{
new MenuItem(){ Text = "Delete", Icon = IconName.Delete, CommandName = "Delete"}
};
}
protected async Task OnItemClick(MenuItem item)
{
if (item.Action != null)
{
item.Action.Invoke();
}
else
{
switch (item.CommandName)
{
case "Delete":
await Task.Delay(1); // do something
break;
}
}
}
protected async Task OnContextMenu(GridRowClickEventArgs args)
{
if (!(args.Item is Employee employee))
return;
SelectedEmployees = new List<Employee> { employee }; // this does not work
if (args.EventArgs is MouseEventArgs mouseEventArgs)
{
await ContextMenuRef.ShowAsync(mouseEventArgs.ClientX, mouseEventArgs.ClientY);
}
}
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Team { get; set; }
}
public class MenuItem
{
public string Text { get; set; }
public string Icon { get; set; }
public Action Action { get; set; }
public string CommandName { get; set; }
}
}
*** Thread created by admin on customer behalf ***
Hello,
When using grid command button edit with the onedit handler shown in this documentation https://docs.telerik.com/blazor-ui/components/grid/editing/inline
There is a bug that causes the grid to reset to the first page when editing the last item on any page that isn't the first. In other words we can edit the last item in the gird on the first page but not on the second, third, fourth...etc.
I have taken out all the logic in my edit handler as well and the problem still presents itself.
Below is the relevenat code sample and I have also zipped a short video demonstrating the behavior.
<TelerikGrid @ref="@GridNameHere"
Class="smallerFont"
Data="@DataHere"
Pageable="true"
Page="@Page"
PageSize="@PageSize"
TotalCount="@Total"
Sortable="@true"
Groupable="@false"
FilterMode="@GridFilterMode.FilterMenu"
Reorderable="@true"
OnEdit="@OnEdit"
OnUpdate="@OnUpdate"
OnCreate="@OnUpdate">
<GridToolBar>
<GridCommandButton Command="Add" Icon="add">Add</GridCommandButton>
</GridToolBar>
<GridColumns>
<GridCommandColumn Width="150px">
<GridCommandButton Command="Edit" Icon="edit">Edit</GridCommandButton>
<GridCommandButton Command="Save" Icon="save" ShowInEdit="true">Save</GridCommandButton>
<GridCommandButton Command="Cancel" Icon="cancel" ShowInEdit="true">Cancel</GridCommandButton>
</GridCommandColumn>
<GridColumn Field="@(nameof(ModelName.FieldName))" Title="Column Name" Width="100px" />
</GridColumns>
</TelerikGrid>
//Handler for edit
protected void OnEdit(GridCommandEventArgs args)
{
// no code in here and problem still presents itself but feel free to put anything I recommend using the sample from the documentation above
}
For example, when I have two levels of grouping, I want to render only the inner footer templates, but not the outer.
While this is possible with some CSS like the snippet below, this does not scale well, and does not work well for arbitrary number of groups
<style>
.k-group-footer + .k-group-footer {
display:none;
}
</style>
Group by the Vacation and Team columns to see the effect
<TelerikGrid Data=@GridData Groupable="true" Pageable="true">
<GridColumns>
<GridColumn Field=@nameof(Employee.Name) Groupable="false" />
<GridColumn Field=@nameof(Employee.Team) Title="Team">
<GroupFooterTemplate>
Team group footer
</GroupFooterTemplate>
</GridColumn>
<GridColumn Field=@nameof(Employee.IsOnLeave) Title="On Vacation">
<GroupFooterTemplate>
IsOnLeave group footer
</GroupFooterTemplate>
</GridColumn>
</GridColumns>
</TelerikGrid>
@code {
public List<Employee> GridData { get; set; }
protected override void OnInitialized()
{
GridData = new List<Employee>();
var rand = new Random();
for (int i = 0; i < 15; i++)
{
GridData.Add(new Employee()
{
EmployeeId = i,
Name = "Employee " + i.ToString(),
Team = "Team " + i % 3,
IsOnLeave = i % 2 == 0
});
}
}
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Team { get; set; }
public bool IsOnLeave { get; set; }
}
}
If the "Navigable" parameter of the Grid is set to false (its default state) and the EditMode is PopUp, there is no focus on the first input in Add/Edit mode.
Hi,
I am using a Blazor TelerikGrid component with Virtual ScrollMode. I have set a fixed Height, PageSize that exceeds the rows that fit in the grid, and a RowHeight which I have confirmed fits the row contents and resolves to a computed Height of the same value (using Chrome Dev Tools -> Computed tab). Everything works fine except that sometimes scrolling does not trigger the OnRead event and the rows displayed after scrolling are placeholders.
I don't experience this problem when I click the scroll arrow buttons (up or down). I don't experience the problem at all if I drag the scroll bar up or down. But if I page up/down, or click on the scroll page area up/down it will sometimes work and sometimes not. If placeholders are shown, I only need to click a scroll button up/down a few times for it to then read and display the correct rows.
To reproduce use the attached VS2019 project, click "Telerik Scroll Issue" nav menu, and in the TelerikGrid click the page down areas of the vertical scrollbar 3 times.
<AdminEdit>
Using the keyboard to save items works inconsistently. When editing an item, hitting enter seems to save the change as expected. When inserting an item, however, the item is lost.
---
ADMIN EDIT
Tthe grid calls the OnUpdate handler again, not OnCreate which results in data loss - the newly inserted item is unlikely to match existing data and so it appears to be lost.
Workaround - call the OnCreate handler yourself when the ID of the record is the default for its type - for example, zero for an integer. This indicates a newly inserted record in the grid.
<TelerikGrid Data=@MyData EditMode="@GridEditMode.Inline" Pageable="true" Height="500px" Navigable="true"
OnUpdate="@UpdateHandler" OnDelete="@DeleteHandler" OnCreate="@CreateHandler" OnCancel="@CancelHandler">
<GridToolBar>
<GridCommandButton Command="Add" Icon="add">Add Employee</GridCommandButton>
</GridToolBar>
<GridColumns>
<GridColumn Field=@nameof(SampleData.ID) Title="ID" Editable="false" />
<GridColumn Field=@nameof(SampleData.Name) Title="Name" />
<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 {
async Task UpdateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
if (item.ID == 0)
{
await CreateHandler(args);
}
else
{
// perform actual data source operations here through your service
await MyService.Update(item);
// update the local view-model data with the service data
await GetGridData();
Console.WriteLine("Update event is fired.");
}
}
async Task DeleteHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
await MyService.Delete(item);
// update the local view-model data with the service data
await GetGridData();
Console.WriteLine("Delete event is fired.");
}
async Task CreateHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// perform actual data source operation here through your service
await MyService.Create(item);
// update the local view-model data with the service data
await GetGridData();
Console.WriteLine("Create event is fired.");
}
async Task CancelHandler(GridCommandEventArgs args)
{
SampleData item = (SampleData)args.Item;
// if necessary, perform actual data source operation here through your service
Console.WriteLine("Cancel event is fired.");
}
// in a real case, keep the models in dedicated locations, this is just an easy to copy and see example
public class SampleData
{
public int ID { get; set; }
public string Name { get; set; }
}
public List<SampleData> MyData { get; set; }
async Task GetGridData()
{
MyData = await MyService.Read();
}
protected override async Task OnInitializedAsync()
{
await GetGridData();
}
// the following static class mimics an actual data service that handles the actual data source
// replace it with your actual service through the DI, this only mimics how the API can look like and works for this standalone page
public static class MyService
{
private static List<SampleData> _data { get; set; } = new List<SampleData>();
public static async Task Create(SampleData itemToInsert)
{
itemToInsert.ID = _data.Count + 1;
_data.Insert(0, itemToInsert);
}
public static async Task<List<SampleData>> Read()
{
if (_data.Count < 1)
{
for (int i = 1; i < 50; i++)
{
_data.Add(new SampleData()
{
ID = i,
Name = "Name " + i.ToString()
});
}
}
return await Task.FromResult(_data);
}
public static async Task Update(SampleData itemToUpdate)
{
var index = _data.FindIndex(i => i.ID == itemToUpdate.ID);
if (index != -1)
{
_data[index] = itemToUpdate;
}
}
public static async Task Delete(SampleData itemToDelete)
{
_data.Remove(itemToDelete);
}
}
}
---
Values of FilterMenu are not preserved in GridState.
If FilterRow is used instead of FilterMenu then the values are preserved in GridState.
(I believe that Filtering was preserved with FilterMenu as well in some previous version but I could be wrong.)
Regards,
René