How to bind a generic model to a TelerikGrid?

2 Answers 239 Views
Grid
Stefan
Top achievements
Rank 1
Iron
Stefan asked on 23 Sep 2021, 11:36 AM | edited on 23 Sep 2021, 11:37 AM

I have built my own component, GenericGrid, which under the hood uses a TelerikGrid. The GenericGrid takes TItem as typeparam which gets passed onto a generic HTTP method that retrieves records from an OData API based on the TItem that gets passed on.

GenericGridTest.razor:

@page "/GenericGrid" @using IndiciaStage.Domain.Entities <GenericGrid TItem="Employee"></GenericGrid> @code { }

 

GenericGrid.razor:

@using Indicia.Grid.Services
@using System.Collections.ObjectModel
@using IndiciaStage.Domain.Entities

@inject LocalStorageService _localStorage
@inject GenericHttpEntityService _entityService

@typeparam TItem

<TelerikGrid @ref="@Grid"
             AutoGenerateColumns="true"
             Height="460px"
             RowHeight="60"
             PageSize="10"
             Pageable="true"
             Sortable="true"
             Resizable="true"
             FilterMode="GridFilterMode.FilterMenu"
             EditMode="GridEditMode.Popup"
             OnRead="@ReadEntity"
             OnStateInit="@((GridStateEventArgs<object> args) => OnStateInitHandler(args))"
             OnStateChanged="@((GridStateEventArgs<object> args) => OnStateChangedHandler(args))">
    <GridColumns>
        <GridAutoGeneratedColumns />
    </GridColumns>
</TelerikGrid>


@code {
    // Grid data
    private List<TItem> GridData { get; set; } = new();
    private int Total { get; set; }
    
    // Parameters
    [Parameter]
    public TItem Entity { get; set; }

    private async Task ReadEntity(GridReadEventArgs args)
    {
        var data = await _entityService.GetAll<TItem>(args.Request);

        GridData = data.Records;
        Total = data.Total;

        StateHasChanged();
    }

 

EntityListResponse.cs (based on the OData Grid sample on GitHub, made generic):

    public class EntityListResponse<T>
    {
        [System.Text.Json.Serialization.JsonPropertyName("value")]
        public List<T> Records { get; set; }
        
        [System.Text.Json.Serialization.JsonPropertyName("@odata.count")]
        public int Total { get; set; }
    }

 

GetAll method in GenericHttpEntityService.cs:

        public async Task<EntityListResponse<T>> GetAll<T>(DataSourceRequest request)
        {
            var name = typeof(T).Name;
            var baseUrl = $"{name}s?";

            var requestUrl = $"{baseUrl}{request.ToODataString()}";

            var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
            requestMessage.Headers.Add("Accept", "application/json");
            var client = HttpClient.CreateClient("IndiciaStageApi");
            var response = await client.SendAsync(requestMessage);

            if (response.IsSuccessStatusCode)
            {
                var body = await response.Content.ReadAsStringAsync();

                var options = new JsonSerializerOptions();
                options.Converters.Add(new JsonStringEnumConverter());
                var oDataResponse = JsonSerializer.Deserialize<EntityListResponse<T>>(body, options);

                return oDataResponse;
            }
            else
            {
                throw new HttpRequestException(
                    "Request failed. I need better error handling, e.g. returning empty data.");
            }
        }

 

What I want to achieve is for the grid columns to be generated automatically based on the object type, Employee in this case, and the retrieved data to be bound to the grid. Sadly, this doesn't seem to work

As you can see, the JSON is deserialized correctly into an EntityListResponse of type Employee. However, I don't know how to bind the data to the grid and autogenerate its corresponding columns. I tried adding Data="@GridData" to the TelerikGrid, but that returns an error because the type of GridData is List<TItem>.

Is there any way to implement what I'm trying to achieve?

2 Answers, 1 is accepted

Sort by
0
Roland
Top achievements
Rank 3
Iron
Iron
Veteran
answered on 24 Sep 2021, 06:32 PM

I am too lazy to study the entire post, but I have done what you did, and you seem to be missing:

@typeparam T

<TelerikGrid @ref="@grid" TItem="T" ...>
0
Radko
Telerik team
answered on 28 Sep 2021, 07:37 AM

Hi Stefan,

What you are doing is essentially wrapping the TelerikGrid with your own generic component. However, the Grid needs to know the type it will receive, and if you are not passing the Data parameter from which the type could be easily inferred, you need to pass a type within the TItem as Roland already suggested.

For example, the code below works correctly(note I have used the Data parameter for simplicity but the same result should be observed once you pass the correct type):

GenericGrid.razor:

@typeparam TItem

<TelerikGrid Data="@GridData"
             AutoGenerateColumns="true">
    <GridColumns>
        <GridAutoGeneratedColumns />
    </GridColumns>
</TelerikGrid>

@code {
    [Parameter]
    public List<TItem> GridData { get; set; } = new();
}

Index.razor:

@page "/"

<GenericGrid GridData="@Data">
</GenericGrid>

@code {
    public class Person
    {
        public int Age { get; set; }
        public string Name { get; set; }
    }

    public List<Person> Data { get; set; } = new List<Person>();

    protected override void OnInitialized() => Data = new List<Person> { new Person { Age = 20, Name = "John" }, new Person { Age = 30, Name = "Dorothy" } };
}

Here is an article from the official docs, where this is mentioned: ASP.NET Core Blazor templated components. I trust this will help you resolve the issue.

Regards, Radko Stanev Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Tags
Grid
Asked by
Stefan
Top achievements
Rank 1
Iron
Answers by
Roland
Top achievements
Rank 3
Iron
Iron
Veteran
Radko
Telerik team
Share this question
or