I set the GridColumn DisplayFormat="{0: yyyy-MM-dd}" and the data reflects that format. The default filter control doesn't. How can I make the control do that?
---
ADMIN EDIT
For the time being, the way to affect the filter behavior is through a custom filter template. The format for date pickers and numeric textboxes comes from the app culture settings (see more here). You may also want to Follow this idea for easier selection of a default filter operator and limiting the filter operators choices.
---
Navigable="true" + OnRead data binding allow the user to go beyond the last Grid page. The component shows no rows, and even though the user can return to previous pages, it's cumbersome.
The workaround is to manage the Page value manually in the PageChanged handler.
@using Telerik.DataSource.Extensions
@* workaround: *@
@*Page="@GridPage"
PageChanged="@OnGridPageChanged"*@
<TelerikGrid OnRead="@OnGridRead"
Navigable="true"
TItem="@Product"
Pageable="true">
<GridColumns>
<GridColumn Field="@nameof(Product.Name)" Title="Product Name" />
</GridColumns>
</TelerikGrid>
@code {
List<Product> GridData { get; set; }
int GridPage { get; set; } = 1;
int GridTotal { get; set; }
// workaround
void OnGridPageChanged(int newPage)
{
if (newPage > 0 && newPage <= Math.Ceiling((double)GridTotal / (double)10))
{
GridPage = newPage;
}
}
void OnGridRead(GridReadEventArgs args)
{
var result = GridData.ToDataSourceResult(args.Request);
args.Data = result.Data;
args.Total = result.Total;
// workaround
//GridTotal = result.Total;
}
protected override void OnInitialized()
{
GridData = new List<Product>();
var rnd = new Random();
for (int i = 1; i <= 12; i++)
{
GridData.Add(new Product()
{
Id = i,
Name = "Product " + i.ToString()
});
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
}
}
When Grid is nested in a Window, pressing Escape key will bubble to the Window causing it to close during edit operation of the Grid.
Hello Team,
I am using "FilterMode="GridFilterMode.FilterRow". For int values there is a "numeric chooser" in the column header and the filter option "contains" is not available.
This is the correct behaviour. But when I bind the column to a ulong, ushort, ... value theses seems to be considered as string. There is no "numeric chooser" and the filter "contains" is available, which resullts in further problems with the OData endpoint.
I noticed Telerik Blazor grid is rendered into two tables. One for the headers and one for the contents.
My assumption is that Allyable Scan expects to find a th element inside the second table and it did not find any. Is my assumption correct?
Element source:
<table role="grid" style="width: ;">
If the Grid has no data, selecting null PageSize throws:
Error: System.ArgumentException: Page Size cannot be less than one (Parameter 'PageSize')
---
ADMIN EDIT
---
A possible workaround for the time being will be to use some conditional CSS to disable the PageSize dropdown while there is no data in the Grid: https://blazorrepl.telerik.com/QcOpkTlb38EDFboT34.
I want to customize the appearance of the header of a certain column, and a bit of CSS backgrounds could help, but I can't do this with the HeaderTemplate alone, nor with content in it because of the padding the cells have.
So, I would like the ability to set the CSS class of the header cell of the column.
The idea of the feature is to be able to customize the list of FilterOperators displayed in the list of the FilterRow and FilterMenu.
FilterRow UI element
FilterMenu UI element
In hierarchical Grid with InCell edit the DateTime cells of the child Grid cannot be edited through the calendar popup. Trying to open the DatePicker or DateTimePicker popup of the child Grid automatically closes the edited cell.
The Grid OnEdit event cannot be cancelled if the user tabs into a cell that should not allow editing.
REPL test page: https://blazorrepl.telerik.com/QcERELbm37c9SzzZ32
Click on "Foo 2" or "Bar 2", and start tabbing. You will be able to edit the values on row 3, which should not happen.
There are two possible workarounds: use a conditional EditorTemplate, or check editability in OnUpdate.
<TelerikGrid Data="@GridData" EditMode="@GridEditMode.Incell" Navigable="true"
OnEdit="@EditItem" OnUpdate="@UpdateItem">
<GridColumns>
<GridColumn Field="@nameof(GridModel.Foo)" Title="Foo (bug)" />
<GridColumn Field="@nameof(GridModel.Bar)" Title="Bar (workaround)">
@*<EditorTemplate>
@{
var item = context as GridModel;
// workaround 1
if (item.IsEditable)
{
<TelerikTextBox @bind-Value="@item.Bar" />
}
else
{
<span class="k-textbox k-input k-rounded-md">
<input class="k-input-inner" tabindex="0" readonly value="@item.Bar" />
</span>
}
}
</EditorTemplate>*@
</GridColumn>
<GridColumn Field="@nameof(GridModel.IsEditable)" Title="Is Row Editable?" Editable="false" />
</GridColumns>
</TelerikGrid>
@code {
List<GridModel> GridData { get; set; }
void EditItem(GridCommandEventArgs args)
{
GridModel item = args.Item as GridModel;
if (!item.IsEditable)
{
args.IsCancelled = true;
}
}
void UpdateItem(GridCommandEventArgs args)
{
var argsItem = args.Item as GridModel;
var index = GridData.FindIndex(i => i.Id == argsItem.Id);
// workaround 2
//if (index != -1 && argsItem.IsEditable)
//{
GridData[index] = argsItem;
//}
}
protected override void OnInitialized()
{
GridData = new List<GridModel>();
for (int i = 1; i <= 5; i++)
{
GridData.Add(new GridModel()
{
Id = i,
Foo = "Foo " + i.ToString(),
Bar = "Bar " + i.ToString(),
IsEditable = i % 2 == 0
});
}
}
public class GridModel
{
public int Id { get; set; }
public string Foo { get; set; }
public string Bar { get; set; }
public bool IsEditable { get; set; }
}
}
The exception is -
System.ArgumentNullException: Value cannot be null. (Parameter 'source')
Here is a test page, based on this one -
@using Telerik.DataSource
@using Telerik.DataSource.Extensions
@using System.IO
<TelerikGrid TItem="@object"
LoadGroupsOnDemand="true"
Groupable="true"
OnStateInit="@((GridStateEventArgs<object> args) => OnStateInitHandler(args))"
OnRead="@ReadItems"
ScrollMode="@GridScrollMode.Virtual" PageSize="20" RowHeight="60"
Navigable="true" Sortable="true" FilterMode="@GridFilterMode.FilterRow" Height="600px">
<GridColumns>
<GridColumn Field="@nameof(Employee.Name)" FieldType="@typeof(string)" Groupable="false" />
<GridColumn Field="@nameof(Employee.Team)" FieldType="@typeof(string)" Title="Team" />
<GridColumn Field="@nameof(Employee.Salary)" FieldType="@typeof(decimal)" Groupable="false" />
<GridColumn Field="@nameof(Employee.IsOnLeave)" FieldType="@typeof(bool)" Title="On Vacation" />
</GridColumns>
</TelerikGrid>
@code {
List<object> GridData { get; set; }
protected async Task ReadItems(GridReadEventArgs args)
{
DataEnvelope<Employee> result = await MyService.GetData(args.Request);
if (args.Request.Groups.Count > 0)
{
args.Data = result.GroupedData.Cast<AggregateFunctionsGroup>().ToList();
}
else
{
args.Data = result.CurrentPageData.Cast<Employee>().ToList();
}
args.Total = result.TotalItemCount;
if (args.Request.Groups.Count > 0)
{
try
{
List<AggregateFunctionsGroup> items = result.GroupedData.Cast<AggregateFunctionsGroup>().ToList();
await using var s = new MemoryStream();
await System.Text.Json.JsonSerializer.SerializeAsync(s, items);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
void OnStateInitHandler(GridStateEventArgs<object> args)
{
// set initial grouping
GridState<object> desiredState = new GridState<object>()
{
GroupDescriptors = new List<GroupDescriptor>()
{
new GroupDescriptor()
{
Member = "Team",
MemberType = typeof(string)
},
new GroupDescriptor()
{
Member = "IsOnLeave",
MemberType = typeof(bool)
}
}
};
args.GridState = desiredState;
}
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Team { get; set; }
public bool IsOnLeave { get; set; }
public decimal Salary { get; set; }
}
public class DataEnvelope<T>
{
public List<AggregateFunctionsGroup> GroupedData { get; set; }
public List<T> CurrentPageData { get; set; }
public int TotalItemCount { get; set; }
}
public static class MyService
{
private static List<Employee> SourceData { get; set; }
public static async Task<DataEnvelope<Employee>> GetData(DataSourceRequest request)
{
if (SourceData == null)
{
SourceData = new List<Employee>();
var rand = new Random();
for (int i = 1; i <= 2500; i++)
{
SourceData.Add(new Employee()
{
EmployeeId = i,
Name = "Employee " + i.ToString(),
Team = "Team " + i % 100,
IsOnLeave = i % 3 == 0,
Salary = rand.Next(1000, 5000)
});
}
}
await Task.Delay(500);// deliberate delay to showcase async operations, remove in a real app
// retrieve data as needed, you can find more examples and runnable projects here
// https://github.com/telerik/blazor-ui/tree/master/grid/datasourcerequest-on-server
var datasourceResult = SourceData.ToDataSourceResult(request);
DataEnvelope<Employee> dataToReturn;
if (request.Groups.Count > 0)
{
dataToReturn = new DataEnvelope<Employee>
{
GroupedData = datasourceResult.Data.Cast<AggregateFunctionsGroup>().ToList(),
TotalItemCount = datasourceResult.Total
};
}
else
{
dataToReturn = new DataEnvelope<Employee>
{
CurrentPageData = datasourceResult.Data.Cast<Employee>().ToList(),
TotalItemCount = datasourceResult.Total
};
}
return await Task.FromResult(dataToReturn);
}
}
}
When a filter descriptor is created and the value is of type DateTime? (nullable DateTime) the serialized value is incorrect.
DataSourceRequest request1 = new()
{
Filters = new[] {new FilterDescriptor("Test", FilterOperator.IsEqualTo, DateTime.Now.Date) {MemberType = typeof(DateTime)}},
Sorts = new List<SortDescriptor>()
};
DataSourceRequest request2 = new()
{
Filters = new[] { new FilterDescriptor("Test", FilterOperator.IsEqualTo, DateTime.Now.Date) { MemberType = typeof(DateTime?) } },
Sorts = new List<SortDescriptor>()
};
string query1 = request1.ToODataString(); // outputs $count=true&$filter=(Test%20eq%202022-05-12T00:00:00.0000000Z)&$skip=0
string query2 = request2.ToODataString(); // outputs $count=true&$filter=(Test%20eq%202022-05-12%2000:00:00)&$skip=0
Currently the blazor grid must be a specific, static height. If one is not provided, the grid uses a default of 500px.
Kendo grid implementations in other UI frameworks allow for more flexibility in the height of the grid. It would be great if the blazor implementation could support this as well.
Two specific scenarios that are valueable:
1) Grid height adjusts to accomodate all of the items in the grid
For other kendo grid implementations, this is typically the case when "Scrollable" is set to false. If there is a plan to allow toggling scrolling for the blazor grid, then I think that this would come along with that.
2) Ability to set grid height to 100%
With other kendo implementations this is normally done via CSS, and is useful for when you want a "full screen" grid. This is normally combined with "Scrollable=true" and often combined with Pagination="true" as well. Currently it's not possible to do this - since the height is defined on the k-grid element, it cannot be overridden with CSS.