Hi,
I've noticed some odd behaviour where the OnRead event is being called twice. Initially I thought it was my code, but I've got to a bizarre example where having two Console.WriteLine statements causes the repeated call, but having one doesn't!
In my testing with more code in the method it hasn't been consistent, so I'm not sure if it's a timing/threading issue. I have tested with the following:
My test code looks like this:
@layout EmptyLayout@page "/testgrid"<TelerikGrid Data=@GridData TotalCount=@Total Pageable=true PageSize=15 OnRead=@ReadItems> <GridColumns> <GridColumn Field=@nameof(Employee.Id) Title="ID" /> <GridColumn Field=@nameof(Employee.Name) Title="Name" /> </GridColumns></TelerikGrid>@code { public List<Employee> GridData { get; set; } public int Total { get; set; } = 0; protected async Task ReadItems(GridReadEventArgs args) { Console.WriteLine("ReadItems 1"); // Remove this line and ReadItems is only called once!!! Console.WriteLine("ReadItems 2"); // Adding this makes no difference //await Task.Delay(1); } public class DataEnvelope { public List<Employee> CurrentPageData { get; set; } public int TotalItemCount { get; set; } } public class Employee { public int Id { get; set; } public string Name { get; set; } }}
Any help appreciated!
Thanks.
This worked in 2.5.1.
Sample repro (focus the textbox and try moving the cursor with the left and right arrows)
<TelerikTabStrip>
<TabStripTab Title="first tab">
<TelerikTextBox Value="@TbValue"></TelerikTextBox>
<input type="text" value="@TbValue" />
</TabStripTab>
<TabStripTab Title="second tab">another tab</TabStripTab>
</TelerikTabStrip>
@code{
string TbValue { get; set; } = "lorem ipsum";
}
Hi,
I'm trying to set an empty column title
<Telerik.Blazor.Components.GridColumn Field="@item.FieldName"
Title=""
Resizable="true"
Width="@width">
I would expect it to show an empty header title but instead fieldName is displayed.
There's a bug when using the popup mode and adding a record
https://demos.telerik.com/blazor-ui/grid/editing-popup
We have a Telerik grid which is customized by some CSS rules. The problem is that the header width does not fill the width of the table if no scrollbar is shown.
My question is: Why did you create the table like it is right now in HTML (See screenshot as well)? In my opinion, it would be easier to use something more simple like described here: https://www.w3schools.com/html/html_tables.asp
<table style="width:100%">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
</table>
This would make it easier to customize the table / grid as well as having no issues with the widths at all. This rectangle on the right top edge doesn't look good...
I'm not sure if this is a feature request or just a discussion / idea for the developers :) I just wanted to bring this in and get an explanation why you chose to do it that way (And maybe get a fix for this as well).
Best regards,
Christian
When you have page numbers that go to 4 digits (>1000), the numbers get cramped up together and it is hard to tell which page you really are on.
Workaround - the CSS at the beginning of the snippet below.
Reproducible - go to the last page on this sample and you will see the results attached below, if you have removed the workaround.
<style> /* The workaround */ .k-pager-wrap.k-grid-pager .k-link, .k-pager-wrap.k-grid-pager .k-state-selected { min-width: calc(10px + 1.4285714286em); width: auto; }</style>@*The MCVE*@@using Telerik.Blazor.Components.Grid<TelerikGrid Data="@MyData" Height="300px" Pageable="true" PageSize="2" Sortable="true"> <TelerikGridColumns> <TelerikGridColumn Field="@(nameof(SampleData.Id))" /> <TelerikGridColumn Field="@(nameof(SampleData.Name))" Title="Employee Name" /> <TelerikGridColumn Field="@(nameof(SampleData.HireDate))" Title="Hire Date" /> </TelerikGridColumns></TelerikGrid>@functions { public IEnumerable<SampleData> MyData = Enumerable.Range(1, 5000).Select(x => new SampleData { Id = x, Name = "name " + x, HireDate = DateTime.Now.AddDays(-x) }); public class SampleData { public int Id { get; set; } public string Name { get; set; } public DateTime HireDate { get; set; } } //in a real case, consider fetching the data in an appropriate event like OnInitAsync //also, consider keeping the models in dedicated locations like a shared library //this is just an example that is easy to copy and run}I had a working server-side Blazor project that was working, but a problem appears to have begun without me changing any code. I upgraded to the latest version (2.4.0) and am having the same problem.
The SelectedItemsChanged event is not working when a checkbox is checked. If I click outside the checkbox in the same column, the event fires however.
I see similar behavior on your own demo page, so this seems like a bug: https://demos.telerik.com/blazor-ui/grid/selection Check some products on that grid and the selected items do not change below. I've tested this in Vivaldi and Edge.
Thanks,
Sean
When clicking on the Add Button in a Grid, a new item is created and displayed in edit mode.
Problem is, the OnEdit event is not triggered. I need to set a default value for new items and added the code in the OnEditHandler with if(args.IsNew){ //set default value}.
Unfortunately this does not work because the event is not triggered. This makes me wonder what "args.IsNew" is for if not for the usecase described above.
@using ClientApp.Shared
@inject HttpClient Http
<TelerikGrid Data=@forecasts Height="550px"
Pageable="true" Sortable="true"
PageSize="20" Groupable="true">
<GridColumns>
<GridColumn Field="Date">
<Template>
@((context as WeatherForecast).Date.ToString("dddd, dd MMM yyyy"))
</Template>
</GridColumn>
<GridColumn Field="TemperatureC" Title="Temp. C" />
<GridColumn Field="TemperatureF" Title="Temp. F" />
<GridColumn Field="Summary" />
</GridColumns>
</TelerikGrid>
@code {
//List<WeatherForecast> forecasts { get; set; } = new List<WeatherForecast>(); // Works fine!
List<WeatherForecast> forecasts { get; set; } //Need to sort a field to show the rows
protected override async Task OnInitializedAsync()
{
//forecasts = new List<WeatherForecast>(); //this helps
forecasts = await Http.GetJsonAsync<List<WeatherForecast>>("WeatherForecast");
//these do not help
//await Task.Delay(200);
//StateHasChanged();
}
}I want to be able to control the page at which the user is in the grid. I will later use that to call my own API through the OnRead event. Binding the Page parameter does not seem to work, however.
Reproducible:
@using Telerik.Blazor.Components.Grid@using Telerik.Blazor.Components.NumericTextBox@using Telerik.DataSource.Extensions;<TelerikNumericTextBox @bind-Value="@startPage"></TelerikNumericTextBox><TelerikGrid Data=@GridData TotalCount=@Total Page="@startPage" Filterable=true Sortable=true Pageable=true EditMode="inline"> <TelerikGridEvents> <EventsManager OnRead=@ReadItems></EventsManager> </TelerikGridEvents> <TelerikGridColumns> <TelerikGridColumn Field=@nameof(Employee.ID) /> <TelerikGridColumn Field=@nameof(Employee.Name) Title="Name" /> <TelerikGridColumn Field=@nameof(Employee.HireDate) Title="Hire Date" /> <TelerikGridCommandColumn> <TelerikGridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</TelerikGridCommandButton> <TelerikGridCommandButton Command="Edit" Icon="edit">Edit</TelerikGridCommandButton> <TelerikGridCommandButton Command="Delete" Icon="delete">Delete</TelerikGridCommandButton> <TelerikGridCommandButton Command="Cancel" Icon="cancel" ShowInEdit="true">Cancel</TelerikGridCommandButton> </TelerikGridCommandColumn> </TelerikGridColumns> <TelerikGridToolBar> <TelerikGridCommandButton Command="Add" Icon="add">Add Employee</TelerikGridCommandButton> </TelerikGridToolBar></TelerikGrid>There is a deliberate delay in the data source operations in this example to mimic real life delays and to showcase the async nature of the calls.@code { int startPage { get; set; } = 2; public List<Employee> SourceData { get; set; } public List<Employee> GridData { get; set; } public int Total { get; set; } = 0; protected override void OnInit() { SourceData = GenerateData(); } protected async Task ReadItems(GridReadEventArgs args) { Console.WriteLine("data requested: " + args.Request); //you need to update the total and data variables //the ToDataSourceResult() extension method can be used to perform the operations over the full data collection //in a real case, you can call data access layer and remote services here instead, to fetch only the necessary data //await Task.Delay(2000); //simulate network delay from a real async call 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 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; } }}while the similar approach works without OnRead:
@using Telerik.Blazor.Components.Grid@using Telerik.Blazor.Components.NumericTextBox<TelerikNumericTextBox @bind-Value="@startPage" Min="1"></TelerikNumericTextBox><TelerikGrid Data="@MyData" Height="300px" Pageable="true" Sortable="true" Page="@startPage" FilterMode="Telerik.Blazor.FilterMode.FilterRow"> <TelerikGridColumns> <TelerikGridColumn Field="@(nameof(SampleData.Id))" /> <TelerikGridColumn Field="@(nameof(SampleData.Name))" Title="Employee Name" /> <TelerikGridColumn Field="@(nameof(SampleData.HireDate))" Title="Hire Date" /> </TelerikGridColumns></TelerikGrid>@code { int startPage { get; set; } = 2; public IEnumerable<SampleData> MyData = Enumerable.Range(1, 50).Select(x => new SampleData { Id = x, Name = "name " + x, HireDate = DateTime.Now.AddDays(-x) }); public class SampleData { public int Id { get; set; } public string Name { get; set; } public DateTime HireDate { get; set; } }}
Steps to reproduce:
1.Create a Telerik Grid with SelectionMode=@GridSelectionMode.Multiple and a GridCheckboxColumn to select/unselect the rows.
Also, bind the selected items to an IEnumerable collection and display the selected items in a <ul>
2.Click on Row1's checkbox - It selects the row, but not checking the checkbox
3.Click on it again- Now it unselects the row, but the checkbox is checked.
4.Click on the SelectAll checkbox in the grid header - It selects all rows, row checkboxes are checked, but the SelectAll checkbox in the grid header remains unchecked.
5.Click on the SelectAll checkbox again - All rows remain selected, row checkboxes remain checked, The SelectAll checkbox is now checked.
6.Click on the SelectAll checkbox again- All rows are unselected, row checkboxes are unchecked, The selectAll checkbox remains checked.
Another issue is, corresponding row checkbox remains checked on moving to next page eventhough the row is not selected.
For eg,
1. a grid of 20 rows displays 10 items per page; Row 2 is selected and checkbox is checked
2. Move to page 2 - Row 12 checkbox is checked (but row 12 is not selected)
Please note that this discrepancy is only when using a checkbox column, otherwise the grid selection using Ctrl + Click works as expected.
Attached Screenshot of one of the issues
On clicking Row 2 checkbox again, result below
Hello,
I want to have the TelerikGrid's "Add" command display a popup for the new record's details, in the same way that the "Edit" functionality does. However with:
<TelerikGrid EditMode="popup">
<TelerikGridToolBar>
<TelerikGridCommandButton Command="Add" Icon="add">Add</TelerikGridCommandButton>
When I click "Add", the new blank row is shown within the grid identical to EditMode="inline", not as a popup. Is the "Add" functionality meant to work in popup mode?
Reproducible below, expected results is that after editing the decimal field you'll get the data under the grid. Actual: either it does not get updated, or the value is always 0.
@using Telerik.Blazor.Components.Grid<TelerikGrid Data=@MyData EditMode="incell" Pageable="true" Height="500px"> <TelerikGridEvents> <EventsManager OnUpdate="@UpdateHandler" OnEdit="@EditHandler" OnDelete="@DeleteHandler" OnCreate="@CreateHandler"></EventsManager> </TelerikGridEvents> <TelerikGridToolBar> <TelerikGridCommandButton Command="Add" Icon="add">Add Employee</TelerikGridCommandButton> </TelerikGridToolBar> <TelerikGridColumns> <TelerikGridColumn Field=@nameof(SampleData.ID) Title="ID" Editable="false" /> <TelerikGridColumn Field=@nameof(SampleData.Name) Title="Name" /> <TelerikGridColumn Field=@nameof(SampleData.SomeDecimal) Title="Some Decimal" /> <TelerikGridCommandColumn> <TelerikGridCommandButton Command="Delete" Icon="delete">Delete</TelerikGridCommandButton> <TelerikGridCommandButton Command="Save" Icon="save" ShowInEdit="true">Update</TelerikGridCommandButton> </TelerikGridCommandColumn> </TelerikGridColumns></TelerikGrid>@lastUpdateOnDecimal@code { public void EditHandler(GridCommandEventArgs args) { SampleData item = (SampleData)args.Item; Console.WriteLine("Edit event is fired for column " + args.Field); } string lastUpdateOnDecimal; public void UpdateHandler(GridCommandEventArgs args) { string fieldName = args.Field; object newVal = args.Value; //you can cast this, if necessary, according to your model SampleData item = (SampleData)args.Item;//you can also use the entire model //perform actual data source operation here //if you have a context added through an @inject statement, you could call its SaveChanges() method //myContext.SaveChanges(); if (fieldName == "SomeDecimal") { lastUpdateOnDecimal = $"decimal for {item.ID} updated to {newVal} on {DateTime.Now}"; } var matchingItem = MyData.FirstOrDefault(c => c.ID == item.ID); if (matchingItem != null) { matchingItem.Name = item.Name; } Console.WriteLine("Update event is fired for " + args.Field + " with value " + args.Value); } public void CreateHandler(GridCommandEventArgs args) { SampleData item = (SampleData)args.Item; //perform actual data source operation here item.ID = MyData.Count; MyData.Add(item); Console.WriteLine("Create event is fired."); } public void DeleteHandler(GridCommandEventArgs args) { SampleData item = (SampleData)args.Item; //perform actual data source operation here //if you have a context added through an @inject statement, you could call its SaveChanges() method //myContext.SaveChanges(); MyData.Remove(item); Console.WriteLine("Delete 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 decimal SomeDecimal { get; set; } } public List<SampleData> MyData { get; set; } protected override void OnInit() { MyData = new List<SampleData>(); for (int i = 0; i < 50; i++) { MyData.Add(new SampleData() { ID = i, Name = "Name " + i.ToString(), SomeDecimal = i }); } }}
Reproducible
@using Telerik.Blazor
@using Telerik.Blazor.Components.Grid
<TelerikGrid Data=@GridData
SelectionMode="GridSelectionMode.Multiple"
@bind-SelectedItems="SelectedItems"
Pageable="true"
Height="400px">
<TelerikGridToolBar>
<TelerikGridCommandButton Command="MyDelete" OnClick="DeleteSelectedAsync"
Enabled=@(SelectedItems?.Count() > 0) Icon="delete">Delete</TelerikGridCommandButton>
<TelerikGridCommandButton Enabled="false" OnClick="DeleteSelectedAsync">I must always be disabled</TelerikGridCommandButton>
</TelerikGridToolBar>
<TelerikGridColumns>
<TelerikGridCheckboxColumn />
<TelerikGridColumn Field=@nameof(Employee.Name) />
<TelerikGridColumn Field=@nameof(Employee.Team) Title="Team" />
</TelerikGridColumns>
</TelerikGrid>
@result
@if (SelectedItems != null)
{
<ul>
@foreach (Employee employee in SelectedItems)
{
<li>
@employee.Name
</li>
}
</ul>
}
@code {
void DeleteSelectedAsync()
{
result = $"On {DateTime.Now} there are {SelectedItems?.Count()} items selected";
}
string result;
public List<Employee> GridData { get; set; }
public IEnumerable<Employee> SelectedItems { 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
});
}
// select Employee with 3 through 5
SelectedItems = GridData.Skip(2).Take(3).ToList();
}
public class Employee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
public string Team { get; set; }
}
}