From a0c46e6d6f6fd23e983b5f31034880185b35b0b3 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Wed, 25 Dec 2024 15:09:02 +0530 Subject: [PATCH] Grid: Select all or Unselect all items programmatically (#988) * Grid: Select all or Unselect all items programmatically --- ...> Grid_Demo_02_A_Multiple_Selection.razor} | 0 ..._Multiple_Selection_Programmatically.razor | 90 +++++++++++++++++++ .../Grid_Selection_Documentation.razor | 14 ++- blazorbootstrap/Components/Grid/Grid.razor.cs | 88 +++++++++++------- 4 files changed, 159 insertions(+), 33 deletions(-) rename BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/{Grid_Demo_02_Multiple_Selection.razor => Grid_Demo_02_A_Multiple_Selection.razor} (100%) create mode 100644 BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_B_Multiple_Selection_Programmatically.razor diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_Multiple_Selection.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_A_Multiple_Selection.razor similarity index 100% rename from BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_Multiple_Selection.razor rename to BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_A_Multiple_Selection.razor diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_B_Multiple_Selection_Programmatically.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_B_Multiple_Selection_Programmatically.razor new file mode 100644 index 000000000..8183601f0 --- /dev/null +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_B_Multiple_Selection_Programmatically.razor @@ -0,0 +1,90 @@ +
+ + +
+ + + + + + @context.Id + + + @context.Name + + + @context.Designation + + + @context.DOJ + + + @context.IsActive + + + + + +
+ Selected Items Count: @selectedEmployees.Count +
+ +
+ Selected Employees: + +
+ +@code { + private Grid gridRef; + private IEnumerable employees = default!; + + private HashSet selectedEmployees = new(); + + private async Task> EmployeesDataProvider(GridDataProviderRequest request) + { + Console.WriteLine("EmployeesDataProvider called..."); + + 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 Employee1 { Id = 107, Name = "Alice", Designation = "AI Engineer", DOJ = new DateOnly(1998, 11, 17), IsActive = true }, + new Employee1 { Id = 103, Name = "Bob", Designation = "Senior DevOps Engineer", DOJ = new DateOnly(1985, 1, 5), IsActive = true }, + new Employee1 { Id = 106, Name = "John", Designation = "Data Engineer", DOJ = new DateOnly(1995, 4, 17), IsActive = true }, + new Employee1 { Id = 104, Name = "Pop", Designation = "Associate Architect", DOJ = new DateOnly(1985, 6, 8), IsActive = false }, + new Employee1 { Id = 105, Name = "Ronald", Designation = "Senior Data Engineer", DOJ = new DateOnly(1991, 8, 23), IsActive = true }, + new Employee1 { Id = 102, Name = "Line", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), IsActive = true }, + new Employee1 { Id = 101, Name = "Daniel", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), IsActive = true }, + new Employee1 { Id = 108, Name = "Zayne", Designation = "Data Analyst", DOJ = new DateOnly(1991, 1, 1), IsActive = true }, + new Employee1 { Id = 109, Name = "Isha", Designation = "App Maker", DOJ = new DateOnly(1996, 7, 1), IsActive = true }, + }; + } + + private Task OnSelectedItemsChanged(HashSet employees) + { + selectedEmployees = employees is not null && employees.Any() ? employees : new(); + return Task.CompletedTask; + } + + private Task SelectAllEmployees() => gridRef.SelectAllItemsAsync(); + + private Task UnselectAllEmployees() => gridRef.UnSelectAllItemsAsync(); +} \ No newline at end of file diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Selection_Documentation.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Selection_Documentation.razor index a2c2fc9a2..1fcd44c02 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Selection_Documentation.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Selection_Documentation.razor @@ -19,11 +19,21 @@ -
+
To select multiple rows, set SelectionMode="GridSelectionMode.Multiple".
- + + +

Selected items are removed from the selection if they are not rendered after paging, sorting, filtering, etc.

+
+
+ +
+
+ Select or unselect all the items programatically by calling the SelectAllItemsAsync() and UnSelectAllItemsAsync() methods. Also, set SelectionMode="GridSelectionMode.Multiple". +
+

Selected items are removed from the selection if they are not rendered after paging, sorting, filtering, etc.

diff --git a/blazorbootstrap/Components/Grid/Grid.razor.cs b/blazorbootstrap/Components/Grid/Grid.razor.cs index 2a90de27b..ee757b060 100644 --- a/blazorbootstrap/Components/Grid/Grid.razor.cs +++ b/blazorbootstrap/Components/Grid/Grid.razor.cs @@ -12,6 +12,10 @@ public partial class Grid : BlazorBootstrapComponentBase private List> columns = new(); + private GridDetailView? detailView; + + public GridEmptyDataTemplate? emptyDataTemplate; + /// /// Current grid state (filters, paging, sorting). /// @@ -21,18 +25,14 @@ public partial class Grid : BlazorBootstrapComponentBase private RenderFragment? headerSelectionTemplate; - private GridDetailView? detailView; - - public GridEmptyDataTemplate? emptyDataTemplate; - - public GridLoadingTemplate? loadingTemplate; - private bool isFirstRenderComplete = false; private List? items = null; private object? lastAssignedDataOrDataProvider; + public GridLoadingTemplate? loadingTemplate; + private int pageSize; private bool requestInProgress = false; @@ -69,7 +69,8 @@ protected override void OnInitialized() protected override Task OnParametersSetAsync() { - if ((Data is null && DataProvider is null) || (Data is not null && DataProvider is not null)) throw new ArgumentException($"Grid requires either {nameof(Data)} or {nameof(DataProvider)}, but not both or neither."); + if ((Data is null && DataProvider is null) || (Data is not null && DataProvider is not null)) + throw new ArgumentException($"Grid requires either {nameof(Data)} or {nameof(DataProvider)}, but not both or neither."); if (AllowPaging && PageSize < 0) throw new ArgumentException($"{nameof(PageSize)} must be greater than zero."); @@ -123,6 +124,10 @@ protected override Task OnParametersSetAsync() /// public async ValueTask ResetPageNumber() => await ResetPageNumberAsync(true); + public Task SelectAllItemsAsync() => SelectAllItemsInternalAsync(true); + + public Task UnSelectAllItemsAsync() => SelectAllItemsInternalAsync(false); + internal void AddColumn(GridColumn column) => columns.Add(column); internal async Task FilterChangedAsync() @@ -158,13 +163,13 @@ internal async Task RefreshDataAsync(bool firstRender = false, CancellationToken await LoadGridSettingsAsync(); var request = new GridDataProviderRequest - { - PageNumber = AllowPaging ? gridCurrentState.PageIndex : 0, - PageSize = AllowPaging ? pageSize : 0, - Sorting = AllowSorting ? gridCurrentState.Sorting ?? GetDefaultSorting()! : null!, - Filters = AllowFiltering ? GetFilters()! : null!, - CancellationToken = cancellationToken - }; + { + PageNumber = AllowPaging ? gridCurrentState.PageIndex : 0, + PageSize = AllowPaging ? pageSize : 0, + Sorting = AllowSorting ? gridCurrentState.Sorting ?? GetDefaultSorting()! : null!, + Filters = AllowFiltering ? GetFilters()! : null!, + CancellationToken = cancellationToken + }; GridDataProviderResult result = default!; @@ -205,6 +210,12 @@ internal async ValueTask ResetPageNumberAsync(bool refreshGrid = false) await RefreshDataAsync(false); } + internal void SetGridDetailView(GridDetailView detailView) => this.detailView = detailView; + + internal void SetGridEmptyDataTemplate(GridEmptyDataTemplate emptyDataTemplate) => this.emptyDataTemplate = emptyDataTemplate; + + internal void SetGridLoadingTemplate(GridLoadingTemplate loadingTemplate) => this.loadingTemplate = loadingTemplate; + internal async Task SortingChangedAsync(GridColumn column) { if (columns == null || !columns.Any()) @@ -380,13 +391,8 @@ private async Task LoadGridSettingsAsync() private async Task OnHeaderCheckboxChanged(ChangeEventArgs args) { - allItemsSelected = bool.TryParse(args?.Value?.ToString(), out var checkboxState) && checkboxState; - selectedItems = allItemsSelected ? new HashSet(items!) : new HashSet(); - SelectedItemsCount = selectedItems.Count; - await CheckOrUnCheckAll(); - - if (SelectedItemsChanged.HasDelegate) - await SelectedItemsChanged.InvokeAsync(selectedItems); + var headerCheckboxState = bool.TryParse(args?.Value?.ToString(), out var checkboxState) && checkboxState; + await SelectAllItemsInternalAsync(headerCheckboxState); } private async Task OnPageChangedAsync(int newPageNumber) @@ -495,13 +501,27 @@ private Task SaveGridSettingsAsync() return GridSettingsChanged.InvokeAsync(settings); } - private async Task SetCheckboxStateAsync(string id, CheckboxState checkboxState) => await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.grid.setSelectAllCheckboxState", id, (int)checkboxState); + private async Task SelectAllItemsInternalAsync(bool selectAll) + { + if(SelectionMode != GridSelectionMode.Multiple) + return; - internal void SetGridDetailView(GridDetailView detailView) => this.detailView = detailView; + allItemsSelected = selectAll; + selectedItems = allItemsSelected ? new HashSet(items!) : new HashSet(); + SelectedItemsCount = allItemsSelected ? selectedItems.Count : 0; - internal void SetGridEmptyDataTemplate(GridEmptyDataTemplate emptyDataTemplate) => this.emptyDataTemplate = emptyDataTemplate; + if (allItemsSelected) + await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Checked); + else + await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Unchecked); - internal void SetGridLoadingTemplate(GridLoadingTemplate loadingTemplate) => this.loadingTemplate = loadingTemplate; + await CheckOrUnCheckAll(); + + if (SelectedItemsChanged.HasDelegate) + await SelectedItemsChanged.InvokeAsync(selectedItems); + } + + private async Task SetCheckboxStateAsync(string id, CheckboxState checkboxState) => await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.grid.setSelectAllCheckboxState", id, (int)checkboxState); /// /// Set filters. @@ -534,9 +554,11 @@ private void SetFilters(IEnumerable filterItems) #region Properties, Indexers protected override string? ClassNames => - BuildClassNames(Class, + BuildClassNames( + Class, ("bb-table", true), - (BootstrapClass.TableSticky, FixedHeader)); + (BootstrapClass.TableSticky, FixedHeader) + ); /// /// Gets or sets the grid delete. @@ -705,8 +727,10 @@ private void SetFilters(IEnumerable filterItems) public string? GridContainerClass { get; set; } private string? GridContainerClassNames => - BuildClassNames(GridContainerClass, - (BootstrapClass.TableResponsive, Responsive)); + BuildClassNames( + GridContainerClass, + (BootstrapClass.TableResponsive, Responsive) + ); /// /// Gets or sets the grid container css style. @@ -715,8 +739,10 @@ private void SetFilters(IEnumerable filterItems) public string? GridContainerStyle { get; set; } private string? GridContainerStyleNames => - BuildStyleNames(GridContainerStyle, - ($"height:{Height.ToString(CultureInfo.InvariantCulture)}{Unit.ToCssString()}", FixedHeader)); + BuildStyleNames( + GridContainerStyle, + ($"height:{Height.ToString(CultureInfo.InvariantCulture)}{Unit.ToCssString()}", FixedHeader) + ); /// /// This event is fired when the grid state is changed.