Skip to content

Commit 91c7257

Browse files
committed
#298, ##593, and #957 - grid selected items
1 parent a0c46e6 commit 91c7257

File tree

6 files changed

+213
-23
lines changed

6 files changed

+213
-23
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<Grid TItem="Employee1"
2+
Class="table table-hover table-bordered"
3+
DataProvider="EmployeesDataProvider"
4+
AllowSelection="true"
5+
@bind-SelectedItems="@selectedEmployees"
6+
Responsive="true">
7+
8+
<GridColumns>
9+
<GridColumn TItem="Employee1" HeaderText="Id" PropertyName="Id">
10+
@context.Id
11+
</GridColumn>
12+
<GridColumn TItem="Employee1" HeaderText="Employee Name" PropertyName="Name">
13+
@context.Name
14+
</GridColumn>
15+
<GridColumn TItem="Employee1" HeaderText="Designation" PropertyName="Designation">
16+
@context.Designation
17+
</GridColumn>
18+
<GridColumn TItem="Employee1" HeaderText="DOJ" PropertyName="DOJ">
19+
@context.DOJ
20+
</GridColumn>
21+
<GridColumn TItem="Employee1" HeaderText="Active" PropertyName="IsActive">
22+
@context.IsActive
23+
</GridColumn>
24+
</GridColumns>
25+
26+
</Grid>
27+
28+
<div class="mt-3">
29+
Selected Items Count: @selectedEmployees.Count
30+
</div>
31+
32+
<div class="mt-2">
33+
Selected Employees:
34+
<ul>
35+
@foreach (var emp in selectedEmployees)
36+
{
37+
<li>@emp.Name</li>
38+
}
39+
</ul>
40+
</div>
41+
42+
@code {
43+
private IEnumerable<Employee1> employees = default!;
44+
45+
private HashSet<Employee1> selectedEmployees = new(){
46+
new Employee1 { Id = 102, Name = "Line", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), IsActive = true }
47+
};
48+
49+
private async Task<GridDataProviderResult<Employee1>> EmployeesDataProvider(GridDataProviderRequest<Employee1> request)
50+
{
51+
Console.WriteLine("EmployeesDataProvider called...");
52+
53+
if (employees is null) // pull employees only one time for client-side filtering, sorting, and paging
54+
employees = GetEmployees(); // call a service or an API to pull the employees
55+
56+
return await Task.FromResult(request.ApplyTo(employees));
57+
}
58+
59+
private IEnumerable<Employee1> GetEmployees()
60+
{
61+
return new List<Employee1>
62+
{
63+
new Employee1 { Id = 107, Name = "Alice", Designation = "AI Engineer", DOJ = new DateOnly(1998, 11, 17), IsActive = true },
64+
new Employee1 { Id = 103, Name = "Bob", Designation = "Senior DevOps Engineer", DOJ = new DateOnly(1985, 1, 5), IsActive = true },
65+
new Employee1 { Id = 106, Name = "John", Designation = "Data Engineer", DOJ = new DateOnly(1995, 4, 17), IsActive = true },
66+
new Employee1 { Id = 104, Name = "Pop", Designation = "Associate Architect", DOJ = new DateOnly(1985, 6, 8), IsActive = false },
67+
new Employee1 { Id = 105, Name = "Ronald", Designation = "Senior Data Engineer", DOJ = new DateOnly(1991, 8, 23), IsActive = true },
68+
new Employee1 { Id = 102, Name = "Line", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), IsActive = true },
69+
new Employee1 { Id = 101, Name = "Daniel", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), IsActive = true },
70+
new Employee1 { Id = 108, Name = "Zayne", Designation = "Data Analyst", DOJ = new DateOnly(1991, 1, 1), IsActive = true },
71+
new Employee1 { Id = 109, Name = "Isha", Designation = "App Maker", DOJ = new DateOnly(1996, 7, 1), IsActive = true },
72+
};
73+
}
74+
75+
private Task OnSelectedItemsChanged(HashSet<Employee1> employees)
76+
{
77+
selectedEmployees = employees is not null && employees.Any() ? employees : new();
78+
return Task.CompletedTask;
79+
}
80+
}

BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Demo_02_A_Multiple_Selection.razor

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<Grid TItem="Employee1"
2-
Class="table table-hover table-bordered"
3-
DataProvider="EmployeesDataProvider"
4-
AllowFiltering="true"
5-
AllowSelection="true"
6-
SelectionMode="GridSelectionMode.Multiple"
7-
SelectedItemsChanged="OnSelectedItemsChanged"
8-
Responsive="true">
2+
Class="table table-hover table-bordered"
3+
DataProvider="EmployeesDataProvider"
4+
AllowFiltering="true"
5+
AllowSelection="true"
6+
SelectionMode="GridSelectionMode.Multiple"
7+
SelectedItemsChanged="OnSelectedItemsChanged"
8+
Responsive="true">
99

1010
<GridColumns>
1111
<GridColumn TItem="Employee1" HeaderText="Id" PropertyName="Id">
@@ -74,7 +74,8 @@
7474

7575
private Task OnSelectedItemsChanged(HashSet<Employee1> employees)
7676
{
77-
selectedEmployees = employees is not null && employees.Any() ? employees : new();
77+
selectedEmployees = employees;
78+
StateHasChanged();
7879
return Task.CompletedTask;
7980
}
8081
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<div class="mb-3">
2+
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" @onclick="SelectAllEmployees">Select All</Button>
3+
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" @onclick="UnselectAllEmployees">Unselect All</Button>
4+
</div>
5+
6+
<Grid @ref="gridRef" TItem="Employee1"
7+
Class="table table-hover table-bordered"
8+
DataProvider="EmployeesDataProvider"
9+
AllowFiltering="true"
10+
AllowSelection="true"
11+
SelectionMode="GridSelectionMode.Multiple"
12+
SelectedItemsChanged="OnSelectedItemsChanged"
13+
Responsive="true">
14+
15+
<GridColumns>
16+
<GridColumn TItem="Employee1" HeaderText="Id" PropertyName="Id">
17+
@context.Id
18+
</GridColumn>
19+
<GridColumn TItem="Employee1" HeaderText="Employee Name" PropertyName="Name">
20+
@context.Name
21+
</GridColumn>
22+
<GridColumn TItem="Employee1" HeaderText="Designation" PropertyName="Designation">
23+
@context.Designation
24+
</GridColumn>
25+
<GridColumn TItem="Employee1" HeaderText="DOJ" PropertyName="DOJ">
26+
@context.DOJ
27+
</GridColumn>
28+
<GridColumn TItem="Employee1" HeaderText="Active" PropertyName="IsActive">
29+
@context.IsActive
30+
</GridColumn>
31+
</GridColumns>
32+
33+
</Grid>
34+
35+
<div class="mt-3">
36+
Selected Items Count: @selectedEmployees.Count
37+
</div>
38+
39+
<div class="mt-2">
40+
Selected Employees:
41+
<ul>
42+
@foreach (var emp in selectedEmployees)
43+
{
44+
<li>@emp.Name</li>
45+
}
46+
</ul>
47+
</div>
48+
49+
@code {
50+
private Grid<Employee1> gridRef;
51+
private IEnumerable<Employee1> employees = default!;
52+
53+
private HashSet<Employee1> selectedEmployees = new();
54+
55+
private async Task<GridDataProviderResult<Employee1>> EmployeesDataProvider(GridDataProviderRequest<Employee1> request)
56+
{
57+
Console.WriteLine("EmployeesDataProvider called...");
58+
59+
if (employees is null) // pull employees only one time for client-side filtering, sorting, and paging
60+
employees = GetEmployees(); // call a service or an API to pull the employees
61+
62+
return await Task.FromResult(request.ApplyTo(employees));
63+
}
64+
65+
private IEnumerable<Employee1> GetEmployees()
66+
{
67+
return new List<Employee1>
68+
{
69+
new Employee1 { Id = 107, Name = "Alice", Designation = "AI Engineer", DOJ = new DateOnly(1998, 11, 17), IsActive = true },
70+
new Employee1 { Id = 103, Name = "Bob", Designation = "Senior DevOps Engineer", DOJ = new DateOnly(1985, 1, 5), IsActive = true },
71+
new Employee1 { Id = 106, Name = "John", Designation = "Data Engineer", DOJ = new DateOnly(1995, 4, 17), IsActive = true },
72+
new Employee1 { Id = 104, Name = "Pop", Designation = "Associate Architect", DOJ = new DateOnly(1985, 6, 8), IsActive = false },
73+
new Employee1 { Id = 105, Name = "Ronald", Designation = "Senior Data Engineer", DOJ = new DateOnly(1991, 8, 23), IsActive = true },
74+
new Employee1 { Id = 102, Name = "Line", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), IsActive = true },
75+
new Employee1 { Id = 101, Name = "Daniel", Designation = "Architect", DOJ = new DateOnly(1977, 1, 12), IsActive = true },
76+
new Employee1 { Id = 108, Name = "Zayne", Designation = "Data Analyst", DOJ = new DateOnly(1991, 1, 1), IsActive = true },
77+
new Employee1 { Id = 109, Name = "Isha", Designation = "App Maker", DOJ = new DateOnly(1996, 7, 1), IsActive = true },
78+
};
79+
}
80+
81+
private Task OnSelectedItemsChanged(HashSet<Employee1> employees)
82+
{
83+
selectedEmployees = employees is not null && employees.Any() ? employees : new();
84+
return Task.CompletedTask;
85+
}
86+
87+
private Task SelectAllEmployees() => gridRef.SelectAllItemsAsync();
88+
89+
private Task UnselectAllEmployees() => gridRef.UnSelectAllItemsAsync();
90+
}

BlazorBootstrap.Demo.RCL/Components/Pages/Grid/06-selection/Grid_Selection_Documentation.razor

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@
1616
Set <code>AllowSelection="true"</code> to enable the selection on the <code>Grid</code>.
1717
By default, <code>SelectionMode</code> is <b>Single</b>.
1818
</div>
19-
<Demo Type="typeof(Grid_Demo_01_Selection)" Tabs="true" />
19+
<Demo Type="typeof(Grid_Demo_01_A_Selection)" Tabs="true" />
20+
</Section>
21+
22+
<Section Size="HeadingSize.H2" Name="Default selection" PageUrl="@pageUrl" Link="default-selection">
23+
<div class="mb-3">
24+
Set <code>AllowSelection="true"</code> to enable the selection on the <code>Grid</code>.
25+
By default, <code>SelectionMode</code> is <b>Single</b>.
26+
</div>
27+
<Demo Type="typeof(Grid_Demo_01_B_Default_Selection)" Tabs="true" />
2028
</Section>
2129

2230
<Section Size="HeadingSize.H2" Name="Multiple selection" PageUrl="@pageUrl" Link="multiple-selection">

blazorbootstrap/Components/Grid/Grid.razor.cs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ public partial class Grid<TItem> : BlazorBootstrapComponentBase
3939

4040
private HashSet<TItem> selectedItems = new();
4141

42-
public int SelectedItemsCount = 0;
43-
4442
private int? totalCount = null;
4543

4644
#endregion
@@ -63,6 +61,7 @@ protected override void OnInitialized()
6361
headerCheckboxId = IdUtility.GetNextId();
6462

6563
pageSize = PageSize;
64+
selectedItems = SelectedItems!;
6665

6766
base.OnInitialized();
6867
}
@@ -93,6 +92,12 @@ protected override Task OnParametersSetAsync()
9392
SaveGridSettingsAsync();
9493
}
9594

95+
if (!mustRefreshData && selectedItems != SelectedItems)
96+
{
97+
mustRefreshData = true;
98+
SelectedItems = selectedItems;
99+
}
100+
96101
// We want to trigger the first data load when we've collected the initial set of columns
97102
// because they might perform some action, like setting the default sort order.
98103
// It would be wasteful to have to re-query immediately.
@@ -192,9 +197,7 @@ internal async Task RefreshDataAsync(bool firstRender = false, CancellationToken
192197
if (AllowSelection)
193198
{
194199
PrepareCheckboxIds();
195-
196-
if (!firstRender)
197-
await RefreshSelectionAsync();
200+
await RefreshSelectionAsync();
198201
}
199202

200203
requestInProgress = false;
@@ -354,7 +357,7 @@ private int GetTotalPagesCount()
354357
/// </summary>
355358
/// <param name="item"></param>
356359
/// <returns>bool</returns>
357-
private bool IsItemSelected(TItem item) => selectedItems.Contains(item);
360+
private bool IsItemSelected(TItem item) => selectedItems?.Contains(item) ?? false;
358361

359362
private async Task LoadGridSettingsAsync()
360363
{
@@ -417,27 +420,27 @@ private async Task OnRowCheckboxChanged(string id, TItem item, ChangeEventArgs a
417420
if (SelectionMode == GridSelectionMode.Multiple)
418421
{
419422
_ = isChecked ? selectedItems.Add(item) : selectedItems.Remove(item);
420-
SelectedItemsCount = selectedItems.Count;
421-
allItemsSelected = SelectedItemsCount == (items?.Count ?? 0);
423+
allItemsSelected = (selectedItems.Count == (items?.Count ?? 0));
422424

423425
if (allItemsSelected)
424426
await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Checked);
425-
else if (SelectedItemsCount == 0)
427+
else if (selectedItems.Count == 0)
426428
await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Unchecked);
427429
else
428430
await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Indeterminate);
429431
}
430432
else
431433
{
432434
selectedItems = isChecked ? new HashSet<TItem> { item } : new HashSet<TItem>();
433-
SelectedItemsCount = selectedItems.Count;
434435
allItemsSelected = false;
435436
await CheckOrUnCheckAll();
436437
await SetCheckboxStateAsync(id, isChecked ? CheckboxState.Checked : CheckboxState.Unchecked);
437438
}
438439

439440
if (SelectedItemsChanged.HasDelegate)
440441
await SelectedItemsChanged.InvokeAsync(selectedItems);
442+
else
443+
SelectedItems = selectedItems;
441444
}
442445

443446
private async Task OnScroll(EventArgs e)
@@ -465,18 +468,19 @@ private async Task RefreshSelectionAsync()
465468
? new HashSet<TItem>()
466469
: selectedItems?.Intersect(items!).ToHashSet() ?? new HashSet<TItem>();
467470

468-
SelectedItemsCount = selectedItems.Count;
469-
allItemsSelected = SelectedItemsCount > 0 && items!.Count == SelectedItemsCount;
471+
allItemsSelected = selectedItems.Count > 0 && items!.Count == selectedItems.Count;
470472

471473
if (allItemsSelected)
472474
await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Checked);
473-
else if (SelectedItemsCount > 0)
475+
else if (selectedItems.Count > 0)
474476
await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Indeterminate);
475477
else
476478
await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Unchecked);
477479

478480
if (SelectedItemsChanged.HasDelegate)
479481
await SelectedItemsChanged.InvokeAsync(selectedItems);
482+
else
483+
SelectedItems = selectedItems;
480484
}
481485

482486
private async Task RowClick(TItem item, EventArgs args)
@@ -508,7 +512,6 @@ private async Task SelectAllItemsInternalAsync(bool selectAll)
508512

509513
allItemsSelected = selectAll;
510514
selectedItems = allItemsSelected ? new HashSet<TItem>(items!) : new HashSet<TItem>();
511-
SelectedItemsCount = allItemsSelected ? selectedItems.Count : 0;
512515

513516
if (allItemsSelected)
514517
await SetCheckboxStateAsync(headerCheckboxId, CheckboxState.Checked);
@@ -519,6 +522,8 @@ private async Task SelectAllItemsInternalAsync(bool selectAll)
519522

520523
if (SelectedItemsChanged.HasDelegate)
521524
await SelectedItemsChanged.InvokeAsync(selectedItems);
525+
else
526+
SelectedItems = selectedItems;
522527
}
523528

524529
private async Task SetCheckboxStateAsync(string id, CheckboxState checkboxState) => await JSRuntime.InvokeVoidAsync("window.blazorBootstrap.grid.setSelectAllCheckboxState", id, (int)checkboxState);
@@ -898,6 +903,12 @@ private void SetFilters(IEnumerable<FilterItem> filterItems)
898903
[Parameter]
899904
public Func<TItem, string>? RowClass { get; set; }
900905

906+
/// <summary>
907+
/// Gets or sets the selected items.
908+
/// </summary>
909+
[Parameter]
910+
public HashSet<TItem>? SelectedItems { get; set; }
911+
901912
/// <summary>
902913
/// This event is fired when the item selection changes.
903914
/// </summary>

0 commit comments

Comments
 (0)