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_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..06d260920 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_01_Summary_Example.razor @@ -0,0 +1,68 @@ + + + + + @context.Id + + + @context.Name + + + @context.Designation + + + @context.DOJ + + + @context.Salary.ToString("C") + + + @context.IsActive + + + + +@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; } + } +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_02_Summary_with_Filters_Paging.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_02_Summary_with_Filters_Paging.razor new file mode 100644 index 000000000..74d65d11c --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Demo_02_Summary_with_Filters_Paging.razor @@ -0,0 +1,83 @@ + + + + + @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_Summary_Documentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor new file mode 100644 index 000000000..362075568 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/16-summary/Grid_Summary_Documentation.razor @@ -0,0 +1,42 @@ +@attribute [Route(pageUrl)] + + + + + @pageDescription + + + + +
+
+ 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. +
+ +
+ GridSummaryColumnType: Average, Count, Max, Min, Sum. Default value is GridSummaryColumnType.None. +
+
+ +
+ +
+ + NOTE: Summaries will be calculated based on the current page data. + + +
+ +@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/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/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/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 +} 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