diff --git a/src/CodeBeam.MudBlazor.Extensions/Components/ComboBox/MudComboBox.razor.cs b/src/CodeBeam.MudBlazor.Extensions/Components/ComboBox/MudComboBox.razor.cs index 1d5c8a0e..ff05ce0d 100644 --- a/src/CodeBeam.MudBlazor.Extensions/Components/ComboBox/MudComboBox.razor.cs +++ b/src/CodeBeam.MudBlazor.Extensions/Components/ComboBox/MudComboBox.razor.cs @@ -625,7 +625,7 @@ public IEnumerable SelectedValues _selectedValues = new HashSet(set, _comparer); - SelectedValuesChanged.InvokeAsync(new HashSet(SelectedValues, _comparer)).CatchAndLog(); + SelectedValuesChanged.InvokeAsync(_selectedValues).CatchAndLog(); ForceUpdateItems().CatchAndLog(); //Console.WriteLine("SelectedValues setter ended"); } @@ -1259,11 +1259,10 @@ protected internal async Task ToggleOption(MudComboBoxItem? item, bool select DeselectAllItems(); await UpdateComboBoxValueAsync(item.Value, updateText: true, updateSearchString: true); } - else if (SelectedValues?.Contains(item.Value) != true) + else if (SelectedValues is not null && SelectedValues.Contains(item.Value) != true) { await SetValueAndUpdateTextAsync(item.Value, false); SelectedValues = SelectedValues.Append(item.Value); - await SelectedValuesChanged.InvokeAsync(_selectedValues); _allSelected = GetAllSelectedState(); //await Task.Delay(1); @@ -1395,14 +1394,14 @@ protected void UpdateIcon() /// /// /// - protected async Task ChipClosed(MudChip chip) + protected Task ChipClosed(MudChip chip) { if (chip is null || SelectedValues is null) - return; + return Task.CompletedTask; //SelectedValues = SelectedValues.Where(x => Converter.Set(x)?.ToString() != chip.Value?.ToString()); SelectedValues = SelectedValues.Where(x => x?.Equals(chip.Value) == false); - await SelectedValuesChanged.InvokeAsync(SelectedValues); + return Task.CompletedTask; } private bool? _allSelected; @@ -1412,26 +1411,19 @@ protected async Task ChipClosed(MudChip chip) /// protected async Task SelectAllItems() { - if (_allSelected == null || _allSelected == false) + if (_allSelected != true) { - SelectedValues = new List(); - foreach (var item in Items.Where(x => x.Eligible)) - { - item.Selected = true; - SelectedValues = SelectedValues.Append(item.Value); - } - await SelectedValuesChanged.InvokeAsync(SelectedValues); + var eligibleItems = Items.Where(x => x.Eligible).ToList(); + foreach (var item in eligibleItems) item.Selected = true; + SelectedValues = [.. eligibleItems.Select(x => x.Value)]; await SetValueAndUpdateTextAsync(SelectedValues.LastOrDefault(), false); _allSelected = true; } else { - foreach (var item in Items.Where(x => x.Selected)) - { - item.Selected = false; - } + var selectedItems = Items.Where(x => x.Selected).ToList(); + foreach (var item in selectedItems) item.Selected = false; SelectedValues = new HashSet(_comparer); - await SelectedValuesChanged.InvokeAsync(SelectedValues); _allSelected = false; } } diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectChipCloseSelectedValuesChanged.razor b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectChipCloseSelectedValuesChanged.razor new file mode 100644 index 00000000..77fc2de3 --- /dev/null +++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectChipCloseSelectedValuesChanged.razor @@ -0,0 +1,22 @@ +@namespace MudExtensions.UnitTests.TestComponents + + + + A + B + C + + +@code { + IEnumerable _selectedValues = new HashSet { "A", "B" }; + public int Count { get; private set; } + + Task SelectedValuesChanged(IEnumerable selectedValues) + { + _selectedValues = selectedValues; + Count++; + return Task.CompletedTask; + } +} diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectSelectAllEnabledSelectedValuesChanged.razor b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectSelectAllEnabledSelectedValuesChanged.razor new file mode 100644 index 00000000..4e7bee46 --- /dev/null +++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectSelectAllEnabledSelectedValuesChanged.razor @@ -0,0 +1,24 @@ +@namespace MudExtensions.UnitTests.TestComponents + + + + @foreach (var character in guids) + { + @character + } + + +@code { + IEnumerable _selectedValues = []; + public int Count { get; private set; } + string[] guids = [.. Enumerable.Range(0, 1000).Select(_ => Guid.NewGuid().ToString())]; + + Task SelectedValuesChanged(IEnumerable selectedValues) + { + _selectedValues = selectedValues; + Count++; + return Task.CompletedTask; + } +} diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectSelectOneSelectedValuesChanged.razor b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectSelectOneSelectedValuesChanged.razor new file mode 100644 index 00000000..aad26b23 --- /dev/null +++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests.Viewer/TestComponents/Combobox/ComboBoxMultiSelectSelectOneSelectedValuesChanged.razor @@ -0,0 +1,22 @@ +@namespace MudExtensions.UnitTests.TestComponents + + + + A + B + C + + +@code { + IEnumerable _selectedValues = []; + public int Count { get; private set; } + + Task SelectedValuesChanged(IEnumerable selectedValues) + { + _selectedValues = selectedValues; + Count++; + return Task.CompletedTask; + } +} diff --git a/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ComboboxTests.cs b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ComboboxTests.cs index f4cece0c..aad6185a 100644 --- a/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ComboboxTests.cs +++ b/tests/CodeBeam.MudBlazor.Extensions.UnitTests/Components/ComboboxTests.cs @@ -194,6 +194,77 @@ public void MultiSelect_SelectAll() combobox.Instance.SelectedValues.Should().BeEquivalentTo(new HashSet()); } + /// + /// When SelectAll is enabled, selecting all items must invoke SelectedValuesChanged exactly once. + /// + [Test] + public void MultiSelect_SelectAllEnabled_SelectedValuesChangedOnce() + { + var comp = Context.Render(); + var combobox = comp.FindComponent>(); + var menu = comp.Find("div.mud-popover"); + var input = combobox.Find("div.mud-input-control"); + input.Click(); + comp.WaitForAssertion(() => menu.ClassList.Should().Contain("mud-popover-open")); + + comp.FindAll("div.mud-combobox-item")[0].Click(); + + comp.WaitForAssertion(() => comp.Instance.Count.Should().Be(1)); + combobox.Instance.SelectedValues.Should().HaveCount(1000); + } + /// + /// Deselecting all items after selecting all must invoke SelectedValuesChanged exactly once more. + /// + [Test] + public void MultiSelect_SelectAllEnabled_DeselectAll_SelectedValuesChangedOnce() + { + var comp = Context.Render(); + var combobox = comp.FindComponent>(); + var menu = comp.Find("div.mud-popover"); + combobox.Find("div.mud-input-control").Click(); + comp.WaitForAssertion(() => menu.ClassList.Should().Contain("mud-popover-open")); + comp.FindAll("div.mud-combobox-item")[0].Click(); + comp.WaitForAssertion(() => combobox.Instance.SelectedValues.Should().HaveCount(1000)); + + comp.FindAll("div.mud-combobox-item")[0].Click(); + + comp.WaitForAssertion(() => combobox.Instance.SelectedValues.Should().BeEmpty()); + comp.Instance.Count.Should().Be(2); + } + + /// + /// Selecting a single item in multi selection must invoke SelectedValuesChanged exactly once. + /// + [Test] + public void MultiSelect_SelectOneItem_SelectedValuesChangedOnce() + { + var comp = Context.Render(); + var combobox = comp.FindComponent>(); + var menu = comp.Find("div.mud-popover"); + combobox.Find("div.mud-input-control").Click(); + comp.WaitForAssertion(() => menu.ClassList.Should().Contain("mud-popover-open")); + + comp.FindAll("div.mud-combobox-item")[0].Click(); + + comp.WaitForAssertion(() => combobox.Instance.SelectedValues.Should().BeEquivalentTo(new[] { "A" })); + comp.Instance.Count.Should().Be(1); + } + + /// + /// Closing a chip must invoke SelectedValuesChanged exactly once. + /// + [Test] + public void MultiSelect_ChipClosed_SelectedValuesChangedOnce() + { + var comp = Context.Render(); + var combobox = comp.FindComponent>(); + + comp.Find("button.mud-chip-close-button").Click(); + + comp.WaitForAssertion(() => combobox.Instance.SelectedValues.Should().HaveCount(1)); + comp.Instance.Count.Should().Be(1); + } + [Test] public async Task ComboBox_MultiSelectEditable() {