Skip to content

Commit

Permalink
#638 [HxMultiSelect] synchronize "SelectAll" checkbox with selected i…
Browse files Browse the repository at this point in the history
…tems - ClearOnHide fix + deselect filtered fix + SelectedValues synchronization
  • Loading branch information
hakenr committed Nov 1, 2023
1 parent d329a89 commit 6f2042b
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 48 deletions.
1 change: 0 additions & 1 deletion BlazorAppTest/Pages/HxMultiSelectTest.razor
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
AllowFiltering="true"
AllowSelectAll="true"
SelectAllText="Select all cultures"
ClearFilterOnHide="false"
Enabled="@enabled"
InputSize="InputSize.Small">
<FilterEmptyResultTemplate>
Expand Down
21 changes: 1 addition & 20 deletions Havit.Blazor.Components.Web.Bootstrap/Forms/HxMultiSelect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,25 +186,6 @@ private void RefreshState()
}
}

private void HandleItemSelectionChanged(List<TItem> itemsSelected, List<TItem> itemsDeselected)
{
var newValue = Value == null ? new List<TValue>() : new List<TValue>(Value);

foreach (var item in itemsDeselected)
{
TValue value = SelectorHelpers.GetValue<TItem, TValue>(ValueSelector, item);
newValue.Remove(value);
}

foreach (var item in itemsSelected)
{
TValue value = SelectorHelpers.GetValue<TItem, TValue>(ValueSelector, item);
newValue.Add(value);
}

CurrentValue = newValue; // setter includes ValueChanged + NotifyFieldChanged
}

protected override bool TryParseValueFromString(string value, out List<TValue> result, out string validationErrorMessage)
{
throw new NotSupportedException();
Expand Down Expand Up @@ -235,8 +216,8 @@ protected override void BuildRenderInput(RenderTreeBuilder builder)
builder.AddAttribute(106, nameof(HxMultiSelectInternal<TValue, TItem>.TextSelector), TextSelector);
builder.AddAttribute(107, nameof(HxMultiSelectInternal<TValue, TItem>.ValueSelector), ValueSelector);
builder.AddAttribute(108, nameof(HxMultiSelectInternal<TValue, TItem>.SelectedValues), Value);
builder.AddAttribute(101, nameof(HxMultiSelectInternal<TValue, TItem>.SelectedValuesChanged), EventCallback.Factory.Create<List<TValue>>(this, value => CurrentValue = value));
builder.AddAttribute(109, nameof(HxMultiSelectInternal<TValue, TItem>.NullDataText), NullDataText);
builder.AddAttribute(110, nameof(HxMultiSelectInternal<TValue, TItem>.OnItemsSelectionChanged), EventCallback.Factory.Create<HxMultiSelectInternal<TValue, TItem>.SelectionChangedArgs>(this, args => HandleItemSelectionChanged(args.ItemsSelected, args.ItemsDeselected)));
builder.AddAttribute(111, nameof(HxMultiSelectInternal<TValue, TItem>.InputGroupStartText), InputGroupStartText);
builder.AddAttribute(112, nameof(HxMultiSelectInternal<TValue, TItem>.InputGroupStartTemplate), InputGroupStartTemplate);
builder.AddAttribute(113, nameof(HxMultiSelectInternal<TValue, TItem>.InputGroupEndText), InputGroupEndText);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,14 @@ public partial class HxMultiSelectInternal<TValue, TItem> : IAsyncDisposable
[Parameter] public List<TItem> ItemsToRender { get; set; }

[Parameter] public List<TValue> SelectedValues { get; set; }
[Parameter] public EventCallback<List<TValue>> SelectedValuesChanged { get; set; }

[Parameter] public Func<TItem, string> TextSelector { get; set; }

[Parameter] public Func<TItem, TValue> ValueSelector { get; set; }

[Parameter] public string NullDataText { get; set; }

[Parameter] public EventCallback<SelectionChangedArgs> OnItemsSelectionChanged { get; set; }

[Parameter] public string InputGroupCssClass { get; set; }

[Parameter] public string InputGroupStartText { get; set; }
Expand Down Expand Up @@ -110,64 +109,52 @@ private async Task EnsureJsModuleAsync()

private async Task HandleItemSelectionChangedAsync(bool newChecked, TItem item)
{
var args = new SelectionChangedArgs();

if (newChecked)
{
args.ItemsSelected.Add(item);

currentSelectedValues = new List<TValue>(currentSelectedValues);
currentSelectedValues.Add(SelectorHelpers.GetValue<TItem, TValue>(ValueSelector, item));
}
else
{
args.ItemsDeselected.Add(item);

currentSelectedValues = new List<TValue>(currentSelectedValues);
currentSelectedValues.Remove(SelectorHelpers.GetValue<TItem, TValue>(ValueSelector, item));
}

SynchronizeSelectAllCheckbox();

await OnItemsSelectionChanged.InvokeAsync(args);
await SelectedValuesChanged.InvokeAsync(currentSelectedValues);
}

private async Task HandleSelectAllClickedAsync()
{
var args = new SelectionChangedArgs();
var filteredItems = GetFilteredItems();

// If all items are already selected then they should be deselected, otherwise only records that aren't selected should be
var newCurrentSelectedValues = new List<TValue>(currentSelectedValues);
if (selectAllChecked)
{
selectAllChecked = false;

foreach (var item in filteredItems)
{
args.ItemsDeselected.Add(item);
newCurrentSelectedValues.Remove(SelectorHelpers.GetValue<TItem, TValue>(ValueSelector, item));
}

currentSelectedValues = new List<TValue>();
}
else
{
selectAllChecked = true;

var newCurrentSelectedValues = new List<TValue>(currentSelectedValues);
foreach (var item in filteredItems)
{
// If the item is already selected we don't need to reselect it
if (!newCurrentSelectedValues.Contains(SelectorHelpers.GetValue<TItem, TValue>(ValueSelector, item)))
{
args.ItemsSelected.Add(item);

newCurrentSelectedValues.Add(SelectorHelpers.GetValue<TItem, TValue>(ValueSelector, item));
}
}
currentSelectedValues = newCurrentSelectedValues;
}
currentSelectedValues = newCurrentSelectedValues;

await OnItemsSelectionChanged.InvokeAsync(args);
await SelectedValuesChanged.InvokeAsync(currentSelectedValues);
}

private void HandleClearIconClick()
Expand Down Expand Up @@ -244,9 +231,10 @@ public Task HandleJsHidden()
{
isShown = false;

if (ClearFilterOnHide && filterText != string.Empty)
if (ClearFilterOnHide && (filterText != string.Empty))
{
filterText = string.Empty;
SynchronizeSelectAllCheckbox();
StateHasChanged();
}

Expand Down Expand Up @@ -284,11 +272,4 @@ protected virtual async ValueTask DisposeAsyncCore()

dotnetObjectReference?.Dispose();
}


public sealed class SelectionChangedArgs
{
public List<TItem> ItemsDeselected { get; set; } = new();
public List<TItem> ItemsSelected { get; set; } = new();
}
}

0 comments on commit 6f2042b

Please sign in to comment.