Completed
Last Updated: 12 Jun 2024 10:51 by ADMIN
Release 2024 Q3 (Aug)
Michael
Created on: 03 Jun 2024 16:20
Category: Grid
Type: Bug Report
2
OnStateInit does not fire if GridAggregates exists but is empty

Reproduceable example: https://blazorrepl.telerik.com/QSEganvg12BVw2ZU37

Steps to reproduce:

  • Add a TelerikGrid to the page - most properties on the grid do not matter for this issue
  • Implement the OnStateInit event
  • Define the GridAggregates render fragment within the TelerikGrid, but leave it empty - do not put any components inside it
  • When the page initializes, note that OnStateInit is never fired

If you remove the GridAggregates emtpy render fragment, or put at least one GridAggregate component in it, OnStateInit fires like expected.

In my project, I've created a component that wraps around the TelerikGrid that I use on all my pages, so that I can have many properties and functions set to reasonable defaults for my use case. My component has an option to conditionally include GridAggregate components within the inner TelerikGrid's GridAggregates render fragment based on separate configuration. If no separate configuration is provided, no GridAggregate components are included, and the GridAggregates render fragment is left blank. Since my component is built in razor markup, there isn't a great option for nulling out that render fragment if it's empty. I had no problems with this exact same code in UI for Blazor version 5.1, and I hope this can be fixed.

3 comments
ADMIN
Tsvetomir
Posted on: 12 Jun 2024 10:51

Hello Michael,

Thank you for coming back with feedback.

As an update about the item, I can confirm that the fix is already in development and it is planned to be shipped in our next release.

I hope the information provided will serve as a good reference for you.

Regards,
Tsvetomir
Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages! Or perhaps, if you are new to our Telerik family, check out our getting started resources!
Michael
Posted on: 06 Jun 2024 13:14
Thanks for taking a look at this! I discovered the same workaround, it just comes with the downside of having to convert my code that builds the aggregates from razor syntax to render tree builder syntax. I look forward to seeing this fixed.
ADMIN
Tsvetomir
Posted on: 06 Jun 2024 12:47

Hello, Michael and everyone affected by this bug,

I apologize for mistakingly marking this bug as a duplicate of the Grid with aggregates never loads if data comes asynchronously regression. The regression masked this bug and we did not cover this scenario. I can confirm that this is a valid bug and our team is already looking into it. Below, I have added a possible workaround where you define the <GridAggregates> tag conditionally. The Conditional Grid ToolBar and DetailTemplate Knowledge-Based article inspire this workaround. 

@using Telerik.DataSource
@using Telerik.DataSource.Extensions

<TelerikGrid TItem="@Employee"
             OnRead="@ReadItems"
             Groupable="true"
             FilterMode="@GridFilterMode.FilterRow"
             Sortable="true"
             OnStateInit="@( (GridStateEventArgs<Employee> args) => OnGridStateInit(args) )"
             Pageable="true"
             GridAggregates="@( HasAggregates ? GridAggregatesTemplate : null )">
    <GridColumns>
        <GridColumn Field=@nameof(Employee.Name) FieldType="@(typeof(string))" Groupable="false" />
        <GridColumn Field=@nameof(Employee.Team) FieldType="@(typeof(string))" Title="Team">
            <GroupHeaderTemplate>
                @context.Value @* the default text you would get without the template *@
                <span>Team size: @context.Count</span>
            </GroupHeaderTemplate>
            <GroupFooterTemplate>
                Team Members: <strong>@context.Count</strong>
            </GroupFooterTemplate>
        </GridColumn>
        <GridColumn Field=@nameof(Employee.IsOnLeave) FieldType="@(typeof(bool))" Title="On Vacation" />
    </GridColumns>
</TelerikGrid>

@code {
    private bool HasAggregates { get; set; } = false;

    private RenderFragment GridAggregatesTemplate { get; set; }  = __builder =>
    {
        // The content of the <GridAggregates> tag goes here
    };

    public List<Employee> SourceData { get; set; }
    private async Task OnGridStateInit(GridStateEventArgs<Employee> args)
    {
        // Sort by Stock
        args.GridState.SortDescriptors.Add(new SortDescriptor()
            {
                Member = nameof(Employee.Name),
                SortDirection = ListSortDirection.Descending
            });

        args.GridState.GroupDescriptors.Add(new GroupDescriptor()
            {
                Member = nameof(Employee.Team),
                MemberType = typeof(string)
            });
    }

    // Handling grouping happens here - by casting the DataSourceResult.Data to objects
    protected async Task ReadItems(GridReadEventArgs args)
    {
        // in this example, we use the Telerik extension methods to shape the data
        // you can, instead, call a service, read more in the following example projects
        // https://github.com/telerik/blazor-ui/tree/master/grid/datasourcerequest-on-server
        var datasourceResult = SourceData.ToDataSourceResult(args.Request);

        // to work with grouping, the grid data needs to be an IEnumerable<object>
        // because grouped data has a different shape than non-grouped data
        // and this is, generally, hidden from you by the grid, but now it cannot be
        args.Data = datasourceResult.Data.Cast<object>().ToList();

        args.Total = datasourceResult.Total;
        args.AggregateResults = datasourceResult.AggregateResults;
    }

    protected override async Task OnInitializedAsync()
    {
        SourceData = GenerateData();
    }

    private List<Employee> GenerateData()
    {
        var result = new List<Employee>();
        var rand = new Random();
        for (int i = 1; i <= 15; i++)
        {
            result.Add(new Employee()
                {
                    EmployeeId = i,
                    Name = "Employee " + i.ToString(),
                    Team = "Team " + i % 3,
                    IsOnLeave = i % 2 == 0
                });
        }

        return result;
    }

    public class Employee
    {
        public int EmployeeId { get; set; }
        public string Name { get; set; }
        public string Team { get; set; }
        public bool IsOnLeave { get; set; }
    }
}

Regards,
Tsvetomir
Progress Telerik

Stay tuned by visiting our public roadmap and feedback portal pages! Or perhaps, if you are new to our Telerik family, check out our getting started resources!