Use RadzenGrid to display a dynamic table

Hi,

I try to use a RadzenGrid to display a dynamic table. The columns of the table are configured in a JSON file, so I don't know in advance what they will be. I am using a List < ExpandoObject > to get the data and can successfully display it but sorting and filtering doesn't work as the underlying code seems to be unable to access the dynamics members in my ExpandoObject. My grid looks like this:

<RadzenGrid AllowFiltering="true" FilterCaseSensitivity="FilterCaseSensitivity.CaseInsensitive" AllowPaging="true" PageSize="20" AllowSorting="true" Data="@result" ColumnWidth="200px">
    <Columns>
        @foreach (var key in columns.Keys)
        {
            <RadzenGridColumn TItem="ExpandoObject" Property="@key" Title="@columns[key].ToString()">
                 <Template Context="data">
                    <span>@((data as IDictionary<string, object>)[key].ToString())</span>
                </Template>
            </RadzenGridColumn>
        }
    </Columns>
</RadzenGrid>

"result" is a List < ExpandoObject > and "columns" a IDictionary < string, object > which contains the columns with an id -> label mapping. At the same time, the ids are members of the ExpandoObject. Displaying the grid works fine, but when I try to sort or filter, I get error messages like this:

warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
  Unhandled exception rendering component: No property or field 'System_Title' exists in type 'ExpandoObject'
No property or field 'System_Title' exists in type 'ExpandoObject' (at index 0)
Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer: Warning: Unhandled exception rendering component: No property or field 'System_Title' exists in type 'ExpandoObject'

Would you have any ideas how to fix this? Or maybe better ideas how to display a dynamically generated table? I also tried using a DataTable or DataView as data element but couldn't figure out how that might work as well

1 Like

Hi @tfenster,

The Radzen Blazor DataGrid uses Linq expressions to perform sorting and filtering (via Dynamic Linq). The latter won't work with ExpandoObjects. You can try using dynamic though. It could work.

I changed

<RadzenGridColumn TItem="ExpandoObject" Property="@key" Title="@columns[key].ToString()"> 
<Template Context="data"> <span>@((data as IDictionary<string, object>)[key].ToString())</span> 
</Template> </RadzenGridColumn>

to

<RadzenGridColumn TItem="dynamic" Property="@key" Title="@columns[key].ToString()"> 
<Template Context="data"> <span>@((data as IDictionary<string, object>)[key].ToString())</span> 
</Template> </RadzenGridColumn>

but that also doesn't work. Would you have any other idea to display a dynamically generated table?

I've switched to another framework which could do this ootb

1 Like

Hi , I'm using LoadData to load data for Grid from api and in my case filtering and sorting works on server.

Thanks for your question it helped me.

 <RadzenGrid AllowFiltering="true" AllowPaging="true" Count="result.TotalCount" PageSize="getUserTableDataInput.MaxResultCount" LoadData="LoadData" AllowSorting="true" Data="@result.Items" ColumnWidth="200px">
        <Columns>
            @foreach (var key in columns.Keys)
            {
                <RadzenGridColumn TItem="ExpandoObject" Property="@key" Title="@columns[key].ToString()">
                    <Template Context="data">
                        <span>@((data as IDictionary<string, object>)[key].ToString())</span>
                    </Template>
                    <FilterTemplate Context="data">
                        <i class="material-icons">search</i>
                        <input @onchange="@((arg)=>SetFilterValue(data.Property,arg))" />
                    </FilterTemplate>
                </RadzenGridColumn>
            }
        </Columns>
    </RadzenGrid>
 async Task LoadData(LoadDataArgs loadData)
    {
        getUserTableDataInput.SkipCount = loadData.Skip ?? 0;
        getUserTableDataInput.OrderBy = loadData.OrderBy;
        getUserTableDataInput.Filter = loadData.Filter;
        await GetUserTableData();
    }

 async Task SetFilterValue(string p, ChangeEventArgs changeEventArgs)
    {
        if (getUserTableDataInput.DictionaryFilter == null)
        {
            getUserTableDataInput.DictionaryFilter = new ConcurrentDictionary<string, object>();
        }
        getUserTableDataInput.DictionaryFilter.AddOrUpdate(p, changeEventArgs.Value, (key, oldValue) => changeEventArgs.Value);
        await GetUserTableData();
    }

1 Like

Would you mind posting a more complete example of your code? I don't see where the results and columns variables are being declared and set. I'm trying to do something similar. You must have created a custom class for your results containing an "Items" and a "TotalCount" field, but I don't know how you are defining the columns.

Hi , I have one custom class for TotalCount and Items.
where ToatlCount is of type int and Items is of type List<ExpandoObject>. Columns is a dictionary.
Dictionary<string, object> columns = new Dictionary<string, object>();
which simply store columns. on which we are iterating.

hope it will help.

Yes, I understand now. Thanks. I didn't realize that the "columns" dictionary was just a property/field on the page.

I've learned as a result of doing some testing using Radzen that its easier to manipulate the service to get the data the way you want it and then pass that data model to the page. If I expose what I want in the data model, then all the native Radzen tools work with it easily.

1 Like

How to make the DataGrid editable with ExpandoObject?

My original requirement was to bind DataTable to DataGrid but researching led me to this post so i transformed my DataTable to ExpandoObject for binding but now I am stuck how to make it editable also? Or any other way because data is dynamics and there could be any number of columns in DataTable.