From 60e5715f70695a24f2ba828bf0e97167f87af3b1 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sun, 23 Mar 2025 17:27:06 +0530 Subject: [PATCH 1/4] Grid summary setup --- .../Components/Layout/MainLayout.razor.cs | 37 ++++---- .../Grid_Demo_16_Summary_Example.razor | 86 +++++++++++++++++++ .../Grid_Summary_Documentation.razor | 26 ++++++ .../Constants/RouteConstants.cs | 1 + .../Components/Grid/GridColumns.razor.cs | 2 +- .../Components/Grid/GridSummaryColumn.razor | 3 + .../Grid/GridSummaryColumn.razor.cs | 5 ++ .../Components/Grid/GridTotalSummary.razor | 2 + .../Components/Grid/GridTotalSummary.razor.cs | 13 +++ 9 files changed, 156 insertions(+), 19 deletions(-) create mode 100644 BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor create mode 100644 BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor create mode 100644 blazorbootstrap/Components/Grid/GridSummaryColumn.razor create mode 100644 blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs create mode 100644 blazorbootstrap/Components/Grid/GridTotalSummary.razor create mode 100644 blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs diff --git a/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs b/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs index d2f9c7d53..225497e49 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs +++ b/BlazorBootstrap.Demo.RCL/Components/Layout/MainLayout.razor.cs @@ -48,23 +48,24 @@ internal override IEnumerable GetNavItems() #region Grid - new (){ Id = "513", Text = "Grid", IconName = IconName.Grid, ParentId = "5" }, - new (){ Id = "51101", Text = "Overview", Href = RouteConstants.Demos_Grid_Overview_Documentation, IconName = IconName.Grid, ParentId = "513" }, // first item - do not change - new (){ Id = "51102", Text = "Alignment", Href = RouteConstants.Demos_Grid_Alignment_Documentation, IconName = IconName.Justify, ParentId = "513" }, - new (){ Id = "51103", Text = "Custom CSS Class", Href = RouteConstants.Demos_Grid_CustomCSSClass_Documentation, IconName = IconName.FileTypeCss, ParentId = "513" }, - new (){ Id = "51104", Text = "Data Binding", Href = RouteConstants.Demos_Grid_DataBinding_Documentation, IconName = IconName.GridFill, ParentId = "513" }, - new (){ Id = "51106", Text = "Detail View", Href = RouteConstants.Demos_Grid_DetailView_Documentation, IconName = IconName.ListNested, ParentId = "513" }, - new (){ Id = "51107", Text = "Events", Href = RouteConstants.Demos_Grid_Events_Documentation, IconName = IconName.LightningChargeFill, ParentId = "513" }, - new (){ Id = "51107", Text = "Filters", Href = RouteConstants.Demos_Grid_Filters_Documentation, IconName = IconName.FunnelFill, ParentId = "513" }, - new (){ Id = "51108", Text = "Fixed Header", Href = RouteConstants.Demos_Grid_FixedHeader_Documentation, IconName = IconName.Table, ParentId = "513" }, - new (){ Id = "51109", Text = "Freeze Columns", Href = RouteConstants.Demos_Grid_FreezeColumns_Documentation, IconName = IconName.LayoutThreeColumns, ParentId = "513" }, - new (){ Id = "51110", Text = "Grid Settings", Href = RouteConstants.Demos_Grid_Settings_Documentation, IconName = IconName.GearFill, ParentId = "513" }, - new (){ Id = "51111", Text = "Nested Grid", Href = RouteConstants.Demos_Grid_NestedGrid_Documentation, IconName = IconName.Pip, ParentId = "513" }, - new (){ Id = "51112", Text = "Paging", Href = RouteConstants.Demos_Grid_Paging_Documentation, IconName = IconName.ChevronBarRight, ParentId = "513" }, - new (){ Id = "51113", Text = "Selection", Href = RouteConstants.Demos_Grid_Selection_Documentation, IconName = IconName.CheckSquareFill, ParentId = "513" }, - new (){ Id = "51114", Text = "Sorting", Href = RouteConstants.Demos_Grid_Sorting_Documentation, IconName = IconName.ArrowDownUp, ParentId = "513" }, - new (){ Id = "51115", Text = "Translations", Href = RouteConstants.Demos_Grid_Translations_Documentation, IconName = IconName.Translate, ParentId = "513" }, - new (){ Id = "51199", Text = "Other", Href = RouteConstants.Demos_Grid_OtherExamples_Documentation, IconName = IconName.PlusSquareFill, ParentId = "513" }, // last item - do not change + new (){ Id = "513", Text = "Grid", IconName = IconName.Grid, ParentId = "5" }, + new (){ Id = "51301", Text = "Overview", Href = RouteConstants.Demos_Grid_Overview_Documentation, IconName = IconName.Grid, ParentId = "513" }, // first item - do not change + new (){ Id = "51302", Text = "Alignment", Href = RouteConstants.Demos_Grid_Alignment_Documentation, IconName = IconName.Justify, ParentId = "513" }, + new (){ Id = "51303", Text = "Custom CSS Class", Href = RouteConstants.Demos_Grid_CustomCSSClass_Documentation, IconName = IconName.FileTypeCss, ParentId = "513" }, + new (){ Id = "51304", Text = "Data Binding", Href = RouteConstants.Demos_Grid_DataBinding_Documentation, IconName = IconName.GridFill, ParentId = "513" }, + new (){ Id = "51306", Text = "Detail View", Href = RouteConstants.Demos_Grid_DetailView_Documentation, IconName = IconName.ListNested, ParentId = "513" }, + new (){ Id = "51307", Text = "Events", Href = RouteConstants.Demos_Grid_Events_Documentation, IconName = IconName.LightningChargeFill, ParentId = "513" }, + new (){ Id = "51307", Text = "Filters", Href = RouteConstants.Demos_Grid_Filters_Documentation, IconName = IconName.FunnelFill, ParentId = "513" }, + new (){ Id = "51308", Text = "Fixed Header", Href = RouteConstants.Demos_Grid_FixedHeader_Documentation, IconName = IconName.Table, ParentId = "513" }, + new (){ Id = "51309", Text = "Freeze Columns", Href = RouteConstants.Demos_Grid_FreezeColumns_Documentation, IconName = IconName.LayoutThreeColumns, ParentId = "513" }, + new (){ Id = "51310", Text = "Grid Settings", Href = RouteConstants.Demos_Grid_Settings_Documentation, IconName = IconName.GearFill, ParentId = "513" }, + new (){ Id = "51311", Text = "Nested Grid", Href = RouteConstants.Demos_Grid_NestedGrid_Documentation, IconName = IconName.Pip, ParentId = "513" }, + new (){ Id = "51312", Text = "Paging", Href = RouteConstants.Demos_Grid_Paging_Documentation, IconName = IconName.ChevronBarRight, ParentId = "513" }, + new (){ Id = "51313", Text = "Selection", Href = RouteConstants.Demos_Grid_Selection_Documentation, IconName = IconName.CheckSquareFill, ParentId = "513" }, + new (){ Id = "51314", Text = "Sorting", Href = RouteConstants.Demos_Grid_Sorting_Documentation, IconName = IconName.ArrowDownUp, ParentId = "513" }, + new (){ Id = "51315", Text = "Summary", Href = RouteConstants.Demos_Grid_Summary_Documentation, IconName = IconName.Calculator, ParentId = "513" }, + new (){ Id = "51316", Text = "Translations", Href = RouteConstants.Demos_Grid_Translations_Documentation, IconName = IconName.Translate, ParentId = "513" }, + new (){ Id = "51399", Text = "Other", Href = RouteConstants.Demos_Grid_OtherExamples_Documentation, IconName = IconName.PlusSquareFill, ParentId = "513" }, // last item - do not change #endregion Grid @@ -106,6 +107,6 @@ internal override IEnumerable GetNavItems() return navItems; } - private async ValueTask OnThemeChanged(string themeName) + private async ValueTask OnThemeChanged(string themeName) => await JS.InvokeVoidAsync("updateDemoCodeThemeCss", themeName); } diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor new file mode 100644 index 000000000..a0193f0a8 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor @@ -0,0 +1,86 @@ + + + + + @context.Id + + + @context.Name + + + @context.IsActive + + + + + + + + + + @emp1.Id + + + @emp1.Description + + + @emp1.Unit + + + @emp1.Quantity + + + + + + + + + +@code { + private List products = new List { + new Product { Id = 10, Name = "Product 10", IsActive = true }, + new Product { Id = 20, Name = "Product 20", IsActive = true }, + new Product { Id = 30, Name = "Product 30", IsActive = true }, + new Product { Id = 40, Name = "Product 40", IsActive = true }, + new Product { Id = 50, Name = "Product 50", IsActive = true } + }; + + private List ingredients = new List { + new Ingredient { Id = 10105, ProductId = 10, Description = "Ingredient 1", Unit = "UNIT1", Quantity = 350 }, + new Ingredient { Id = 10106, ProductId = 10, Description = "Ingredient 2", Unit = "UNIT1", Quantity = 600 }, + new Ingredient { Id = 10107, ProductId = 10, Description = "Ingredient 3", Unit = "UNIT2", Quantity = 13 }, + new Ingredient { Id = 10108, ProductId = 10, Description = "Ingredient 4", Unit = "UNIT3", Quantity = 25 }, + new Ingredient { Id = 20109, ProductId = 20, Description = "Ingredient 5", Unit = "UNIT1", Quantity = 750 }, + new Ingredient { Id = 20110, ProductId = 20, Description = "Ingredient 3", Unit = "UNIT2", Quantity = 13 }, + new Ingredient { Id = 10111, ProductId = 10, Description = "Ingredient 4", Unit = "UNIT3", Quantity = 25 }, + new Ingredient { Id = 20112, ProductId = 20, Description = "Ingredient 5", Unit = "UNIT1", Quantity = 750 }, + new Ingredient { Id = 40113, ProductId = 40, Description = "Ingredient 3", Unit = "UNIT2", Quantity = 13 }, + new Ingredient { Id = 50114, ProductId = 50, Description = "Ingredient 4", Unit = "UNIT3", Quantity = 25 }, + new Ingredient { Id = 20115, ProductId = 20, Description = "Ingredient 5", Unit = "UNIT1", Quantity = 750 }, + }; + + private IEnumerable GetIngredients(int productId) => ingredients.Where(i => i.ProductId == productId); + + public record class Product + { + public int Id { get; set; } + public string? Name { get; set; } + public bool IsActive { get; set; } + } + + public record class Ingredient + { + public int Id { get; set; } + public int ProductId { get; set; } + public string? Description { get; set; } + public string? Unit { get; set; } + public int Quantity { get; set; } + } +} diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor new file mode 100644 index 000000000..e267cfaa6 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor @@ -0,0 +1,26 @@ +@attribute [Route(pageUrl)] + + + + + @pageDescription + + + + +
+
To enable detail view, set the AllowDetailView parameter to true. In the following example, existing <GridColumn> tags are nested under <GridColumns> tag to distinguish them from <GridDetailView>.
+ +
+ +@code { + private const string pageUrl = RouteConstants.Demos_Grid_Summary_Documentation; + private const string pageTitle = "Blazor Grid - Summary"; + private const string pageDescription = "Use Blazor Bootstrap grid component to display tabular data from the data source. And it supports client-side and server-side filtering, paging, and sorting."; + private const string metaTitle = "Blazor Grid Component - Summary"; + private const string metaDescription = "Use Blazor Bootstrap grid component to display tabular data from the data source. And it supports client-side and server-side filtering, paging, and sorting."; + private const string imageUrl = "https://i.imgur.com/eetvhBB.png"; +} diff --git a/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs b/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs index b6459f054..46226db46 100644 --- a/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs +++ b/BlazorBootstrap.Demo.RCL/Constants/RouteConstants.cs @@ -66,6 +66,7 @@ public static class RouteConstants public const string Demos_Grid_Paging_Documentation = Demos_Grid_Prefix + "/paging"; public const string Demos_Grid_Selection_Documentation = Demos_Grid_Prefix + "/selection"; public const string Demos_Grid_Sorting_Documentation = Demos_Grid_Prefix + "/sorting"; + public const string Demos_Grid_Summary_Documentation = Demos_Grid_Prefix + "/summary"; public const string Demos_Grid_Translations_Documentation = Demos_Grid_Prefix + "/translations"; public const string Demos_Grid_OtherExamples_Documentation = Demos_Grid_Prefix + "/other"; #endregion Grid diff --git a/blazorbootstrap/Components/Grid/GridColumns.razor.cs b/blazorbootstrap/Components/Grid/GridColumns.razor.cs index 09a263a7f..663227127 100644 --- a/blazorbootstrap/Components/Grid/GridColumns.razor.cs +++ b/blazorbootstrap/Components/Grid/GridColumns.razor.cs @@ -6,7 +6,7 @@ public partial class GridColumns : BlazorBootstrapComponentBase /// Specifies the content to be rendered inside the grid columns component. /// /// - /// Default value is null. + /// Default value is . /// [Parameter] public RenderFragment? ChildContent { get; set; } = default!; diff --git a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor new file mode 100644 index 000000000..a33f21979 --- /dev/null +++ b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor @@ -0,0 +1,3 @@ +@namespace BlazorBootstrap +@inherits BlazorBootstrapComponentBase +@typeparam TItem diff --git a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs new file mode 100644 index 000000000..0a84af7f9 --- /dev/null +++ b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs @@ -0,0 +1,5 @@ +namespace BlazorBootstrap; + +public partial class GridSummaryColumn : BlazorBootstrapComponentBase +{ +} diff --git a/blazorbootstrap/Components/Grid/GridTotalSummary.razor b/blazorbootstrap/Components/Grid/GridTotalSummary.razor new file mode 100644 index 000000000..3745f80e7 --- /dev/null +++ b/blazorbootstrap/Components/Grid/GridTotalSummary.razor @@ -0,0 +1,2 @@ +@namespace BlazorBootstrap +@inherits BlazorBootstrapComponentBase diff --git a/blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs b/blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs new file mode 100644 index 000000000..894676df9 --- /dev/null +++ b/blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs @@ -0,0 +1,13 @@ +namespace BlazorBootstrap; + +public partial class GridTotalSummary : BlazorBootstrapComponentBase +{ + /// + /// Specifies the content to be rendered inside the grid columns component. + /// + /// + /// Default value is . + /// + [Parameter] + public RenderFragment? ChildContent { get; set; } = default!; +} From f33e8afa415cfe06cb260b9561f5daa044174cf4 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sun, 23 Mar 2025 19:51:25 +0530 Subject: [PATCH 2/4] Grid summary updates --- .../Grid_Demo_16_Summary_Example.razor | 127 +++++++++--------- .../Grid_Summary_Documentation.razor | 16 ++- blazorbootstrap/Components/Grid/Grid.razor | 62 ++++++--- blazorbootstrap/Components/Grid/Grid.razor.cs | 46 +++++++ .../Components/Grid/GridColumn.razor.cs | 18 +++ .../Grid/GridSummaryColumn.razor.cs | 17 +++ .../Enums/GridSummaryColumnType.cs | 11 ++ 7 files changed, 213 insertions(+), 84 deletions(-) create mode 100644 blazorbootstrap/Enums/GridSummaryColumnType.cs diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor index a0193f0a8..74d65d11c 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor @@ -1,86 +1,83 @@ - + - + @context.Id - + @context.Name - + + @context.Designation + + + @context.DOJ + + + @context.Salary.ToString("C") + + @context.IsActive - - - - - - - - @emp1.Id - - - @emp1.Description - - - @emp1.Unit - - - @emp1.Quantity - - - - - - - @code { - private List products = new List { - new Product { Id = 10, Name = "Product 10", IsActive = true }, - new Product { Id = 20, Name = "Product 20", IsActive = true }, - new Product { Id = 30, Name = "Product 30", IsActive = true }, - new Product { Id = 40, Name = "Product 40", IsActive = true }, - new Product { Id = 50, Name = "Product 50", IsActive = true } - }; + private IEnumerable employees = default!; + + private HashSet selectedEmployees = new(); - private List ingredients = new List { - new Ingredient { Id = 10105, ProductId = 10, Description = "Ingredient 1", Unit = "UNIT1", Quantity = 350 }, - new Ingredient { Id = 10106, ProductId = 10, Description = "Ingredient 2", Unit = "UNIT1", Quantity = 600 }, - new Ingredient { Id = 10107, ProductId = 10, Description = "Ingredient 3", Unit = "UNIT2", Quantity = 13 }, - new Ingredient { Id = 10108, ProductId = 10, Description = "Ingredient 4", Unit = "UNIT3", Quantity = 25 }, - new Ingredient { Id = 20109, ProductId = 20, Description = "Ingredient 5", Unit = "UNIT1", Quantity = 750 }, - new Ingredient { Id = 20110, ProductId = 20, Description = "Ingredient 3", Unit = "UNIT2", Quantity = 13 }, - new Ingredient { Id = 10111, ProductId = 10, Description = "Ingredient 4", Unit = "UNIT3", Quantity = 25 }, - new Ingredient { Id = 20112, ProductId = 20, Description = "Ingredient 5", Unit = "UNIT1", Quantity = 750 }, - new Ingredient { Id = 40113, ProductId = 40, Description = "Ingredient 3", Unit = "UNIT2", Quantity = 13 }, - new Ingredient { Id = 50114, ProductId = 50, Description = "Ingredient 4", Unit = "UNIT3", Quantity = 25 }, - new Ingredient { Id = 20115, ProductId = 20, Description = "Ingredient 5", Unit = "UNIT1", Quantity = 750 }, - }; + private async Task> EmployeesDataProvider(GridDataProviderRequest request) + { + if (employees is null) // pull employees only one time for client-side filtering, sorting, and paging + employees = GetEmployees(); // call a service or an API to pull the employees - private IEnumerable GetIngredients(int productId) => ingredients.Where(i => i.ProductId == productId); + return await Task.FromResult(request.ApplyTo(employees)); + } - public record class Product + private IEnumerable GetEmployees() { - public int Id { get; set; } - public string? Name { get; set; } - public bool IsActive { get; set; } + return new List + { + new Employee { Id = 107, Name = "Alice", Designation = "AI Engineer", DOJ = new DateOnly(1998, 11, 17), Salary = 7700, IsActive = true }, + new Employee { Id = 103, Name = "Bob", Designation = "Senior DevOps Engineer", DOJ = new DateOnly(1985, 1, 5), Salary = 19000, IsActive = true }, + new Employee { Id = 106, Name = "John", Designation = "Data Engineer", DOJ = new DateOnly(1995, 4, 17), Salary = 12000, IsActive = true }, + new Employee { Id = 104, Name = "Pop", Designation = "Associate Architect", DOJ = new DateOnly(1985, 6, 8), Salary = 19000, IsActive = false }, + new Employee { Id = 105, Name = "Ronald", Designation = "Senior Data Engineer", DOJ = new DateOnly(1991, 8, 23), Salary = 16500.50f, IsActive = true }, + new Employee { Id = 102, Name = "Line", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), Salary = 24000, IsActive = true }, + new Employee { Id = 101, Name = "Daniel", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), Salary = 21000, IsActive = true }, + new Employee { Id = 113, Name = "Merlin", Designation = "Senior Consultant", DOJ = new DateOnly(1989, 10, 2), Salary = 13500, IsActive = true }, + new Employee { Id = 117, Name = "Sharna", Designation = "Data Analyst", DOJ = new DateOnly(1994, 5, 12), Salary = 15800.10f, IsActive = true }, + new Employee { Id = 108, Name = "Zayne", Designation = "Data Analyst", DOJ = new DateOnly(1991, 1, 1), Salary = 14000, IsActive = true }, + new Employee { Id = 109, Name = "Isha", Designation = "App Maker", DOJ = new DateOnly(1996, 7, 1), Salary = 8000, IsActive = true }, + new Employee { Id = 111, Name = "Glenda", Designation = "Data Engineer", DOJ = new DateOnly(1994, 1, 12), Salary = 17850, IsActive = true }, + }; } - public record class Ingredient + private Task OnSelectedItemsChanged(HashSet employees) + { + selectedEmployees = employees is not null && employees.Any() ? employees : new(); + return Task.CompletedTask; + } + + public record class Employee { public int Id { get; set; } - public int ProductId { get; set; } - public string? Description { get; set; } - public string? Unit { get; set; } - public int Quantity { get; set; } + public string? Name { get; set; } + public string? Designation { get; set; } + public DateOnly DOJ { get; set; } + public float Salary { get; set; } + public bool IsActive { get; set; } } -} +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor index e267cfaa6..0f9ae7884 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor @@ -12,8 +12,20 @@
-
To enable detail view, set the AllowDetailView parameter to true. In the following example, existing <GridColumn> tags are nested under <GridColumns> tag to distinguish them from <GridDetailView>.
- +
+ To enable summaries on columns, set the AllowSummary parameter to true at the Grid level. Additionally, set the SummaryType parameter on each GridColumn. +
+ In the following example, the Employee Name column has SummaryType set to GridSummaryColumnType.Count, and the Salary column has SummaryType set to GridSummaryColumnType.Sum and SummaryValueDisplayFormat set to C to display the sum of salaries in currency format. +
+ +
+ Supported enumeration values for GridSummaryColumnType are: Average, Count, Max, Min, Sum +
+
+ Default value is GridSummaryColumnType.None. +
+
+
@code { diff --git a/blazorbootstrap/Components/Grid/Grid.razor b/blazorbootstrap/Components/Grid/Grid.razor index 0f1b3936c..41399356c 100644 --- a/blazorbootstrap/Components/Grid/Grid.razor +++ b/blazorbootstrap/Components/Grid/Grid.razor @@ -7,7 +7,11 @@ @if (columns.Any()) -{ +{ + var columnCount = columns.Where(c => c.IsVisible).Count(); + if (AllowSelection) columnCount += 1; + if (AllowDetailView) columnCount += 1; +
@@ -67,17 +71,17 @@ @if (column.Filterable) { + FilterButtonColor="@column.FilterButtonColor" + FilterButtonCSSClass="@column.FilterButtonCSSClass" + FilterOperator="@column.FilterOperator" + FilterValue="@column.FilterValue" + FilterWidth="@column.FilterTextboxWidth" + FiltersTranslationProvider="GridFiltersTranslationProviderAsync!" + FixedHeader="@FixedHeader" + GridColumnFilterChanged="async args => await column.OnFilterChangedAsync(args, column)" + PropertyType="@column.GetPropertyType()" + PropertyTypeName="@column.GetPropertyTypeName()" + Unit="@column.FilterTextboxWidthUnit" /> } } @@ -85,11 +89,6 @@ } - @{ - var columnCount = columns.Where(c => c.IsVisible).Count(); - if (AllowSelection) columnCount += 1; - if (AllowDetailView) columnCount += 1; - } @if (requestInProgress) //|| totalCount is null { @if (loadingTemplate is null) @@ -191,6 +190,35 @@ } } + @if (AllowSummary) + { + + + @if (totalCount > 0) + { + @if (AllowSelection) + { + + } + foreach (var column in columns) + { + @if (!column.IsVisible) + { + continue; + } + else if (column.SummaryType == GridSummaryColumnType.None) + { + + } + else if (column.SummaryType != GridSummaryColumnType.None) + { + + } + } + } + + + }
@GetColumnSummaryValue(column.SummaryType, column.PropertyName, column.SummaryValueDisplayFormat)
diff --git a/blazorbootstrap/Components/Grid/Grid.razor.cs b/blazorbootstrap/Components/Grid/Grid.razor.cs index 8d3946c1d..473713c42 100644 --- a/blazorbootstrap/Components/Grid/Grid.razor.cs +++ b/blazorbootstrap/Components/Grid/Grid.razor.cs @@ -123,6 +123,43 @@ protected override Task OnParametersSetAsync() .Where(column => column.Filterable && column.GetFilterOperator() != FilterOperator.None && !string.IsNullOrWhiteSpace(column.GetFilterValue())) ?.Select(column => new FilterItem(column.PropertyName, column.GetFilterValue(), column.GetFilterOperator(), column.StringComparison)); + private string GetColumnSummaryValue(GridSummaryColumnType type, string propertyName, string format) + { + string? prefix = null; + double value = 0; + + if (type == GridSummaryColumnType.Average) + { + prefix = "Avg"; + value = items?.Average(x => Convert.ToDouble(x.GetType().GetProperty(propertyName)?.GetValue(x))) ?? 0; + } + else if (type == GridSummaryColumnType.Count) + { + prefix = "Count"; + value = items?.Where(x => x.GetType().GetProperty(propertyName)?.GetValue(x) is not null).Count() ?? 0; + } + else if (type == GridSummaryColumnType.Max) + { + prefix = "Max"; + value = items?.Max(x => Convert.ToDouble(x.GetType().GetProperty(propertyName)?.GetValue(x))) ?? 0; + } + else if (type == GridSummaryColumnType.Min) + { + prefix = "Min"; + value = items?.Min(x => Convert.ToDouble(x.GetType().GetProperty(propertyName)?.GetValue(x))) ?? 0; + } + else if (type == GridSummaryColumnType.Sum) + { + prefix = "Total"; + value = items?.Sum(x => Convert.ToDouble(x.GetType().GetProperty(propertyName)?.GetValue(x))) ?? 0; + } + + if (string.IsNullOrWhiteSpace(format)) + return $"{prefix}: {value}"; + else + return $"{prefix}: {value.ToString(format)}"; + } + /// /// Refresh the grid data. /// @@ -652,6 +689,15 @@ private void SetFilters(IEnumerable filterItems) [Parameter] public bool AllowSorting { get; set; } + /// + /// Gets or sets the grid summary. + /// + /// Default value is . + /// + /// + [Parameter] + public bool AllowSummary { get; set; } + /// /// Automatically hides the paging controls when the grid item count is less than or equal to the /// and this property is set to `true`. diff --git a/blazorbootstrap/Components/Grid/GridColumn.razor.cs b/blazorbootstrap/Components/Grid/GridColumn.razor.cs index 3fc98aebe..aee83d14b 100644 --- a/blazorbootstrap/Components/Grid/GridColumn.razor.cs +++ b/blazorbootstrap/Components/Grid/GridColumn.razor.cs @@ -494,6 +494,24 @@ private async Task OnSortClickAsync() [Parameter] public StringComparison StringComparison { get; set; } = StringComparison.OrdinalIgnoreCase; + /// + /// Gets or sets the summary column type. + /// + /// Default value is . + /// + /// + [Parameter] + public GridSummaryColumnType SummaryType { get; set; } = GridSummaryColumnType.None; + + /// + /// Gets or sets the summary value display format. + /// + /// Default value is . + /// + /// + [Parameter] + public string? SummaryValueDisplayFormat { get; set; } + /// /// Gets or sets the text alignment. /// diff --git a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs index 0a84af7f9..cee5763b9 100644 --- a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs +++ b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs @@ -2,4 +2,21 @@ public partial class GridSummaryColumn : BlazorBootstrapComponentBase { + /// + /// Gets or sets the summary column type. + /// + /// Default value is . + /// + /// + [Parameter] + public GridSummaryColumnType SummaryType { get; set; } = GridSummaryColumnType.None; + + /// + /// Gets or sets the property name. + /// + /// Default value is . + /// + /// + [Parameter] + public string PropertyName { get; set; } = default!; } diff --git a/blazorbootstrap/Enums/GridSummaryColumnType.cs b/blazorbootstrap/Enums/GridSummaryColumnType.cs new file mode 100644 index 000000000..a7234d1d3 --- /dev/null +++ b/blazorbootstrap/Enums/GridSummaryColumnType.cs @@ -0,0 +1,11 @@ +namespace BlazorBootstrap; + +public enum GridSummaryColumnType +{ + None, + Average, + Count, + Max, + Min, + Sum +} From d7bb62ea15577e0d6b853afcfecf8a30922cc7e7 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sun, 23 Mar 2025 20:26:21 +0530 Subject: [PATCH 3/4] Demos updated --- .../Grid_Demo_01_Summary_Example.razor | 76 +++++++++++++++++++ ...Demo_02_Summary_with_Filters_Paging.razor} | 0 .../Grid_Summary_Documentation.razor | 14 ++-- .../Components/Grid/GridSummaryColumn.razor | 3 - .../Grid/GridSummaryColumn.razor.cs | 22 ------ .../Components/Grid/GridTotalSummary.razor | 2 - .../Components/Grid/GridTotalSummary.razor.cs | 13 ---- 7 files changed, 85 insertions(+), 45 deletions(-) create mode 100644 BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor rename BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/{Grid_Demo_16_Summary_Example.razor => Grid_Demo_02_Summary_with_Filters_Paging.razor} (100%) delete mode 100644 blazorbootstrap/Components/Grid/GridSummaryColumn.razor delete mode 100644 blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs delete mode 100644 blazorbootstrap/Components/Grid/GridTotalSummary.razor delete mode 100644 blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor new file mode 100644 index 000000000..1275ae63b --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor @@ -0,0 +1,76 @@ + + + + + @context.Id + + + @context.Name + + + @context.Designation + + + @context.DOJ + + + @context.Salary.ToString("C") + + + @context.IsActive + + + + +@code { + private IEnumerable employees = default!; + + private HashSet selectedEmployees = new(); + + private async Task> EmployeesDataProvider(GridDataProviderRequest request) + { + if (employees is null) // pull employees only one time for client-side filtering, sorting, and paging + employees = GetEmployees(); // call a service or an API to pull the employees + + return await Task.FromResult(request.ApplyTo(employees)); + } + + private IEnumerable GetEmployees() + { + return new List + { + new Employee { Id = 107, Name = "Alice", Designation = "AI Engineer", DOJ = new DateOnly(1998, 11, 17), Salary = 7700, IsActive = true }, + new Employee { Id = 103, Name = "Bob", Designation = "Senior DevOps Engineer", DOJ = new DateOnly(1985, 1, 5), Salary = 19000, IsActive = true }, + new Employee { Id = 106, Name = "John", Designation = "Data Engineer", DOJ = new DateOnly(1995, 4, 17), Salary = 12000, IsActive = true }, + new Employee { Id = 104, Name = "Pop", Designation = "Associate Architect", DOJ = new DateOnly(1985, 6, 8), Salary = 19000, IsActive = false }, + new Employee { Id = 105, Name = "Ronald", Designation = "Senior Data Engineer", DOJ = new DateOnly(1991, 8, 23), Salary = 16500.50f, IsActive = true }, + new Employee { Id = 102, Name = "Line", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), Salary = 24000, IsActive = true }, + new Employee { Id = 101, Name = "Daniel", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), Salary = 21000, IsActive = true }, + new Employee { Id = 113, Name = "Merlin", Designation = "Senior Consultant", DOJ = new DateOnly(1989, 10, 2), Salary = 13500, IsActive = true }, + new Employee { Id = 117, Name = "Sharna", Designation = "Data Analyst", DOJ = new DateOnly(1994, 5, 12), Salary = 15800.10f, IsActive = true }, + new Employee { Id = 108, Name = "Zayne", Designation = "Data Analyst", DOJ = new DateOnly(1991, 1, 1), Salary = 14000, IsActive = true }, + new Employee { Id = 109, Name = "Isha", Designation = "App Maker", DOJ = new DateOnly(1996, 7, 1), Salary = 8000, IsActive = true }, + new Employee { Id = 111, Name = "Glenda", Designation = "Data Engineer", DOJ = new DateOnly(1994, 1, 12), Salary = 17850, IsActive = true }, + }; + } + + private Task OnSelectedItemsChanged(HashSet employees) + { + selectedEmployees = employees is not null && employees.Any() ? employees : new(); + return Task.CompletedTask; + } + + public record class Employee + { + public int Id { get; set; } + public string? Name { get; set; } + public string? Designation { get; set; } + public DateOnly DOJ { get; set; } + public float Salary { get; set; } + public bool IsActive { get; set; } + } +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_02_Summary_with_Filters_Paging.razor similarity index 100% rename from BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_16_Summary_Example.razor rename to BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_02_Summary_with_Filters_Paging.razor diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor index 0f9ae7884..362075568 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor @@ -19,13 +19,17 @@
- Supported enumeration values for GridSummaryColumnType are: Average, Count, Max, Min, Sum -
-
- Default value is GridSummaryColumnType.None. + GridSummaryColumnType: Average, Count, Max, Min, Sum. Default value is GridSummaryColumnType.None.
- + + + +
+ + NOTE: Summaries will be calculated based on the current page data. + +
@code { diff --git a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor deleted file mode 100644 index a33f21979..000000000 --- a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor +++ /dev/null @@ -1,3 +0,0 @@ -@namespace BlazorBootstrap -@inherits BlazorBootstrapComponentBase -@typeparam TItem diff --git a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs b/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs deleted file mode 100644 index cee5763b9..000000000 --- a/blazorbootstrap/Components/Grid/GridSummaryColumn.razor.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace BlazorBootstrap; - -public partial class GridSummaryColumn : BlazorBootstrapComponentBase -{ - /// - /// Gets or sets the summary column type. - /// - /// Default value is . - /// - /// - [Parameter] - public GridSummaryColumnType SummaryType { get; set; } = GridSummaryColumnType.None; - - /// - /// Gets or sets the property name. - /// - /// Default value is . - /// - /// - [Parameter] - public string PropertyName { get; set; } = default!; -} diff --git a/blazorbootstrap/Components/Grid/GridTotalSummary.razor b/blazorbootstrap/Components/Grid/GridTotalSummary.razor deleted file mode 100644 index 3745f80e7..000000000 --- a/blazorbootstrap/Components/Grid/GridTotalSummary.razor +++ /dev/null @@ -1,2 +0,0 @@ -@namespace BlazorBootstrap -@inherits BlazorBootstrapComponentBase diff --git a/blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs b/blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs deleted file mode 100644 index 894676df9..000000000 --- a/blazorbootstrap/Components/Grid/GridTotalSummary.razor.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace BlazorBootstrap; - -public partial class GridTotalSummary : BlazorBootstrapComponentBase -{ - /// - /// Specifies the content to be rendered inside the grid columns component. - /// - /// - /// Default value is . - /// - [Parameter] - public RenderFragment? ChildContent { get; set; } = default!; -} From 71cacce9ed1b78f4553c585bf5b3720fd1fa7158 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Sun, 23 Mar 2025 20:37:03 +0530 Subject: [PATCH 4/4] Docs updated --- .../Grid_Demo_01_Summary_Example.razor | 8 -- docs/docs/05-components/grid.mdx | 86 ++++++++++++++++++- 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor index 1275ae63b..06d260920 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor @@ -29,8 +29,6 @@ @code { private IEnumerable employees = default!; - private HashSet selectedEmployees = new(); - private async Task> EmployeesDataProvider(GridDataProviderRequest request) { if (employees is null) // pull employees only one time for client-side filtering, sorting, and paging @@ -58,12 +56,6 @@ }; } - private Task OnSelectedItemsChanged(HashSet employees) - { - selectedEmployees = employees is not null && employees.Any() ? employees : new(); - return Task.CompletedTask; - } - public record class Employee { public int Id { get; set; } diff --git a/docs/docs/05-components/grid.mdx b/docs/docs/05-components/grid.mdx index 7e1d6cca9..ea8e9a0e2 100644 --- a/docs/docs/05-components/grid.mdx +++ b/docs/docs/05-components/grid.mdx @@ -101,6 +101,8 @@ Grid requires either `Data` or `DataProvider` parameter, but not both. | SortKeySelector | `Expression>` | | | Expression used for sorting. | 1.0.0 | | SortString | string | null | | Gets or sets the column sort string. This string is passed to the backend/API for sorting. And it is ignored for client-side sorting. | 1.0.0 | | StringComparison | `StringComparison` | `StringComparison.OrdinalIgnoreCase` | | Gets or sets the StringComparison. Use `StringComparison.CurrentCulture` or `StringComparison.CurrentCultureIgnoreCase` or `StringComparison.InvariantCulture` or `StringComparison.InvariantCultureIgnoreCase` or `StringComparison.Ordinal` or `StringComparison.OrdinalIgnoreCase`. | 1.0.0 | +| SummaryType | `GridSummaryColumnType` | `GridSummaryColumnType.None` | | Gets or sets the summary type. Supported values are `GridSummaryColumnType.None`, `GridSummaryColumnType.Count`, `GridSummaryColumnType.Sum`, `GridSummaryColumnType.Average`, `GridSummaryColumnType.Min`, `GridSummaryColumnType.Max`. | 3.4.0 | +| SummaryValueDisplayFormat | string | null | | Gets or sets the summary value display format. | 3.4.0 | | TextAlignment | `Alignment` | `Alignment.Start` | | Gets or sets the text alignment. Use `Alignment.Start` or `Alignment.Center` or `Alignment.End`. | 1.0.0 | | TextNoWrap | bool | false | | Gets or sets text nowrap. | 1.0.0 | | IsVisible | bool | true | | Gets or sets visibility of the Grid column. | 3.4.0 | @@ -4187,4 +4189,86 @@ Set the IsVisible parameter to **false** to hide the column. } ``` -[See demo here](https://demos.blazorbootstrap.com/grid/other#hide-columns) \ No newline at end of file +[See demo here](https://demos.blazorbootstrap.com/grid/other#hide-columns) + +### Summary + +To enable summaries on columns, set the `AllowSummary` parameter to **true** at the Grid level. Additionally, set the `SummaryType` parameter on each GridColumn. +In the following example, the Employee Name column has `SummaryType` set to **GridSummaryColumnType.Count**, and the **Salary** column has `SummaryType` set to **GridSummaryColumnType.Sum** and `SummaryValueDisplayFormat` set to **C** to display the sum of salaries in currency format. + +Blazor Bootstrap: Grid Component - Summary + +```cshtml {} showLineNumbers + + + + + @context.Id + + + @context.Name + + + @context.Designation + + + @context.DOJ + + + @context.Salary.ToString("C") + + + @context.IsActive + + + +``` + +```cshtml {} showLineNumbers +@code { + private IEnumerable employees = default!; + + private async Task> EmployeesDataProvider(GridDataProviderRequest request) + { + if (employees is null) // pull employees only one time for client-side filtering, sorting, and paging + employees = GetEmployees(); // call a service or an API to pull the employees + + return await Task.FromResult(request.ApplyTo(employees)); + } + + private IEnumerable GetEmployees() + { + return new List + { + new Employee { Id = 107, Name = "Alice", Designation = "AI Engineer", DOJ = new DateOnly(1998, 11, 17), Salary = 7700, IsActive = true }, + new Employee { Id = 103, Name = "Bob", Designation = "Senior DevOps Engineer", DOJ = new DateOnly(1985, 1, 5), Salary = 19000, IsActive = true }, + new Employee { Id = 106, Name = "John", Designation = "Data Engineer", DOJ = new DateOnly(1995, 4, 17), Salary = 12000, IsActive = true }, + new Employee { Id = 104, Name = "Pop", Designation = "Associate Architect", DOJ = new DateOnly(1985, 6, 8), Salary = 19000, IsActive = false }, + new Employee { Id = 105, Name = "Ronald", Designation = "Senior Data Engineer", DOJ = new DateOnly(1991, 8, 23), Salary = 16500.50f, IsActive = true }, + new Employee { Id = 102, Name = "Line", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), Salary = 24000, IsActive = true }, + new Employee { Id = 101, Name = "Daniel", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), Salary = 21000, IsActive = true }, + new Employee { Id = 113, Name = "Merlin", Designation = "Senior Consultant", DOJ = new DateOnly(1989, 10, 2), Salary = 13500, IsActive = true }, + new Employee { Id = 117, Name = "Sharna", Designation = "Data Analyst", DOJ = new DateOnly(1994, 5, 12), Salary = 15800.10f, IsActive = true }, + new Employee { Id = 108, Name = "Zayne", Designation = "Data Analyst", DOJ = new DateOnly(1991, 1, 1), Salary = 14000, IsActive = true }, + new Employee { Id = 109, Name = "Isha", Designation = "App Maker", DOJ = new DateOnly(1996, 7, 1), Salary = 8000, IsActive = true }, + new Employee { Id = 111, Name = "Glenda", Designation = "Data Engineer", DOJ = new DateOnly(1994, 1, 12), Salary = 17850, IsActive = true }, + }; + } + + public record class Employee + { + public int Id { get; set; } + public string? Name { get; set; } + public string? Designation { get; set; } + public DateOnly DOJ { get; set; } + public float Salary { get; set; } + public bool IsActive { get; set; } + } +} +``` + +[See demo here](https://demos.blazorbootstrap.com/grid/summary) \ No newline at end of file