Because the shape of our business objects is not something your grid is easily bound to, we are attempting to generate ExpandoOjbects on the fly and bind to them. In the picture below you can see that Id is not binding correctly. Name is showing up because a column Template was used and that seems to work fine. However, when attempting to use an EditorTemplate we get the RuntimeBinderException shown below.
@page "/dynamic-vendor"
Hi,
I cant see what it is that's causing this error. evertime i run my app, i get the follwoing error below:
Microsoft.AspNetCore.Components.Reflection.ComponentProperties.ThrowForUnknownIncomingParameterName(Type targetType, string parameterName
@page "/Table"
@inject IPurchaseOrderRepository purchaseOrderRepository
@using Telerik.Blazor.Components.Grid
<h3>Table</h3>
<TelerikGrid Data=@auditEventTypeDTOs>
<TelerikGridColumn Field="AuditEventName">
</TelerikGridColumn>
</TelerikGrid>
@code{
public IEnumerable<AuditEventTypeDTO> auditEventTypeDTOs { get; set; }
protected override async Task OnInitializedAsync()
{
auditEventTypeDTOs = await purchaseOrderRepository.GetAllAuditEventTypes();
}
}
The IEnumerable object 'auditEventTypeDTOs' is getting the data from the repository and i've made sure that i don't have any component with the same name within Telerik.blazor namespace.
Do let me know if you need me me to supply more information.
many thanks in advance
George.
The need is to update, add or delete a lot of items at once (for example, the selected items). Sample of batch editing: https://demos.telerik.com/kendo-ui/grid/editing.
Perhaps this may become possible through methods on the grid that invoke the CUD operations.
---
ADMIN EDIT
There is a sample project that accomplishes most of these goals: https://github.com/telerik/blazor-ui/tree/master/grid/batch-editing
The grid state offers a great deal of flexibility in terms of controlling the grid, up to putting it in edit/insert mode.
---
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; }
}
}
Telerik Blazor version 1.5.0 Trial
Steps to reproduce:
This behaviour is inconsistent as the user is required to press the Update button to save a new row, but not to save changes for an existing row. Can the grid be made to retain the new row when the Add button is pressed (or can we have that option)?
I think the base issue here is that the new row isn't added automatically when the cell/row loses focus. The same issue therefore occurs if you press one of the page buttons at the bottom of the grid at step 3 instead.
Here is how this page looks on mac, multiple browsers: https://demos.telerik.com/blazor-ui/grid/grouping
Notice that the columns are misaligned. I believe this is because the scrollbar isn't rendered on a mac if it is "disabled" (there is nothing to scroll).
Probably the best solution would be for it to render like this on all browsers, but have the columns line up (get rid of the spacer in the end of the header row) as the 'empty' scrollbar is not attractive :)
If we enable grouping on a grid which has `FilterMode="Telerik.Blazor.FilterMode.FilterRow"` then we can no longer successfully get focus into any of the filter row edit controls.
Clicking on filter text input box (I think you need to do it a few times) causes a js error and does not put the text input focus into the filter text input.
JS exception is:
telerik-blazor.js:35 Uncaught TypeError: Cannot read property 'getAttribute' of null
at t.value (telerik-blazor.js:35)
Hello,
I'm trying the grid component and I'm able to add a row to the grid using the embbed editor. But I wanted to add an item externally to the list:
<button @onclick="@MyClick">Add item</button>
void MyClick()
{
MyData.Add(new SampleData() { ID = 46, Name = "from click" });
StateHasChanged();
}
The new line does not appear on the grid but if I add a second item through the embbed editor then I get the 2 items!
I also try to replace the List<MyData> by an ObservableCollection<MyData> unsuccessfully.
Thanks & regards,
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
; }
}
}
I need the ability to show or hide command buttons based on a row's property.
I am aware that I can just cancel commands, but in my opinion, a command button should not even be shown when the command can't or shouldn't be executed on a row.
Unfortunately, I was unable to find a way to access the "context" (the instance) in a TelerikGridCommandColumn the same way you're able to in a normal TelerikGridColumn.
---
ADMIN EDIT
You can Vote for and Follow this request for a follow up on providing the model as context to the command column: https://feedback.telerik.com/blazor/1461283-pass-the-model-context-to-command-button. At the moment, conditional command buttons are possible in a "normal" column through the grid state, the page above shows an example.
---
---
ADMIN EDIT: Check the source code and comments in it from the following demo to see how to bind the grid to a DataTable: https://demos.telerik.com/blazor-ui/grid/data-table. You can also examine it offline - the entire demos project is available in the "demos" folder of your installation
The sample code snippet below will let the grid show data, but will not enable complex operations like filtering and sorting. Review the demo linked above for more details on the correct approach.
---
I would like to be able to supply a DataTable with an arbitrary amount of columns to the grid and display them all without declaring them all. This should also allow paging, sorting, filtering. At the moment binding to a DataTable is not supported, only IEnumerable collections are.
At the moment, here's the closest I can get, sorting and filtering throw errors so they are disabled.
@
using
System.Data
@
using
Telerik.Blazor
@
using
Telerik.Blazor.Components.Grid
<button
class
=
"btn btn-primary"
@onclick=
"@LoadData"
>Load Data</button>
@
if
(@d !=
null
)
{
<TelerikGrid Data=@d.AsEnumerable() TItem=
"DataRow"
Sortable=
"false"
Filterable=
"false"
Pageable=
"true"
PageSize=
"3"
Height=
"400px"
>
<TelerikGridColumns>
@
foreach
(DataColumn col
in
d.Columns)
{
<TelerikGridColumn Field=
"@col.ColumnName"
Title=
"@col.ColumnName"
>
<Template>
@((context
as
DataRow).ItemArray[col.Ordinal].ToString())
</Template>
</TelerikGridColumn>
}
</TelerikGridColumns>
</TelerikGrid>
}
@functions {
DataTable d =
null
;
void
LoadData()
{
d = GetData();
}
public
DataTable GetData()
{
DataTable table =
new
DataTable();
table.Columns.Add(
"Product"
,
typeof
(
string
));
table.Columns.Add(
"Price"
,
typeof
(
double
));
table.Columns.Add(
"Quantity"
,
typeof
(
int
));
table.Columns.Add(
"AvailableFrom"
,
typeof
(DateTime));
table.Rows.Add(
"Product 1"
, 10.1, 2, DateTime.Now);
table.Rows.Add(
"Product 2"
, 1.50, 10, DateTime.Now);
table.Rows.Add(
"Product 3"
, 120.66, 5, DateTime.Now);
table.Rows.Add(
"Product 4"
, 30.05, 10, DateTime.Now);
return
table;
}
}
Sometimes, we just want a simple equal filter in grid, without operators options
---
ADMIN EDIT
If you want to modify the current behavior and layout of the filters, use the filter template (there is another example in this thread - in the post from 29 Jun 2020 that you can also use as base).
---
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
});
}
}
}