Skip to content

Commit

Permalink
[Select] Fix multiple issues (#2840)
Browse files Browse the repository at this point in the history
* Fix #2813 , #2830

* Fix tests by reverting earlier change

* Remove listbox multipe example (as it does not work)

* Fix #2832
  • Loading branch information
vnbaaij authored Oct 22, 2024
1 parent 09e4e86 commit 286b4f1
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 48 deletions.
3 changes: 2 additions & 1 deletion examples/Demo/Shared/Pages/Lab/IssueTester.razor
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@

@using FluentUI.Demo.Shared.Pages.List.Select.Examples
<SelectMultiple />
2 changes: 0 additions & 2 deletions examples/Demo/Shared/Pages/List/Listbox/ListboxPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@

<DemoSection Title="Long list with Width and Height" Component="@typeof(ListboxSize)"></DemoSection>

<DemoSection Title="Multiple (not working yet!!)" Component="@typeof(ListboxMultiple)"></DemoSection>

<DemoSection Title="Option template" Component="@typeof(ListboxWithOptionTemplate)"></DemoSection>

<h2 id="documentation">Documentation</h2>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@
SelectedOptions = Data.People.Skip(2).Take(2);
SelectedValue = SelectedOptions.First().PersonId.ToString();
}
}
}
2 changes: 1 addition & 1 deletion examples/Demo/Shared/Shared/EmptyLayout.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@inherits LayoutComponentBase

<div style="overflow: auto;">
<div style="margin: 1.5rem; overflow: auto; height: 800px;">
@Body
</div>
3 changes: 2 additions & 1 deletion src/Core/Components/List/ListComponentBase.razor
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
Value="@GetOptionValue(item)"
Selected="@GetOptionSelected(item)"
Disabled="@(GetOptionDisabled(item) ?? false)"
OnSelect="@OnSelectCallback(item)">
OnSelect="@OnSelectCallback(item)"
aria-selected="@(GetOptionSelected(item) ? "true" : "false")">
@if (OptionTemplate is not null)
{
@OptionTemplate(item)
Expand Down
108 changes: 66 additions & 42 deletions src/Core/Components/List/ListComponentBase.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
// MIT License - Copyright (c) Microsoft Corporation. All rights reserved.
// ------------------------------------------------------------------------

using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.FluentUI.AspNetCore.Components.Extensions;
using Microsoft.FluentUI.AspNetCore.Components.Utilities;
using Microsoft.JSInterop;
using System.Diagnostics.CodeAnalysis;

namespace Microsoft.FluentUI.AspNetCore.Components;

Expand Down Expand Up @@ -209,57 +209,78 @@ public override async Task SetParametersAsync(ParameterView parameters)
isSetValue = true;
newValue = (string?)parameter.Value;
break;
case nameof(Items):
if (Items is not null)
{
newSelectedOption = Items.FirstOrDefault(i => OptionSelected?.Invoke(i) == true);
newValue = GetOptionValue(newSelectedOption);
}
break;
default:
break;
}
}

if (isSetSelectedOption && !Equals(_currentSelectedOption, newSelectedOption))
if (newSelectedOption is not null || newValue is not null || Value is not null)
{
if (Items != null)
if (isSetSelectedOption && !Equals(_currentSelectedOption, newSelectedOption))
{
if (Items.Contains(newSelectedOption))
if (Items != null)
{
_currentSelectedOption = newSelectedOption;
// Make value follow new selected option
Value = GetOptionValue(_currentSelectedOption);
if (Items.Contains(newSelectedOption))
{
_currentSelectedOption = newSelectedOption;
// Make value follow new selected option
Value = GetOptionValue(_currentSelectedOption);
await ValueChanged.InvokeAsync(Value);
}
else
{
// If the selected option is not in the list of items, reset the selected option
_currentSelectedOption = SelectedOption = default;
// and also reset the value
Value = null;
await SelectedOptionChanged.InvokeAsync(SelectedOption);
}
}
else
{
// If the selected option is not in the list of items, reset the selected option
_currentSelectedOption = SelectedOption = default;
// and also reset the value
Value = null;
await SelectedOptionChanged.InvokeAsync(SelectedOption);
// If Items is null, we don't know if the selected option is in the list of items, so we just set it
_currentSelectedOption = newSelectedOption;
}
}
else
{
// If Items is null, we don't know if the selected option is in the list of items, so we just set it
_currentSelectedOption = newSelectedOption;
}
}
else if (isSetValue && Items != null && GetOptionValue(_currentSelectedOption) != newValue)
{
newSelectedOption = Items.FirstOrDefault(item => GetOptionValue(item) == newValue);

if (newSelectedOption != null)
{
_currentSelectedOption = SelectedOption = newSelectedOption;
}
else
if (isSetValue && newValue is null)
{
// If the selected option is not in the list of items, reset the selected option
_currentSelectedOption = SelectedOption = default;
if (this is not FluentCombobox<TOption>)
// Check if one of the Items is selected
if (Items is not null)
{
Value = null;
await ValueChanged.InvokeAsync(Value);
newSelectedOption = Items.FirstOrDefault(item => OptionSelected?.Invoke(item) == true);
if (newSelectedOption is not null)
{
_currentSelectedOption = SelectedOption = newSelectedOption;
newValue = GetOptionValue(_currentSelectedOption);
}
}
}

await SelectedOptionChanged.InvokeAsync(SelectedOption);
if (newValue is null)
{
// If the selected option is not in the list of items, reset the selected option
_currentSelectedOption = SelectedOption = default;

if (this is not FluentCombobox<TOption>)
{
Value = null;
await ValueChanged.InvokeAsync(Value);
}
}
else
{
Value = newValue;
await ValueChanged.InvokeAsync(Value);
}
await SelectedOptionChanged.InvokeAsync(SelectedOption);
}
}
}

Expand Down Expand Up @@ -323,9 +344,9 @@ protected override void OnParametersSet()

if (Multiple)
{
if (SelectedOptions != null && _selectedOptions != SelectedOptions)
if (SelectedOptions != null && SelectedOptions.Any() && _selectedOptions != SelectedOptions)
{
_selectedOptions = new List<TOption>(SelectedOptions);
_selectedOptions = [.. SelectedOptions];
}

if (SelectedOptions == null && Items != null && OptionSelected != null)
Expand Down Expand Up @@ -501,8 +522,8 @@ this is FluentCombobox<TOption> ||

SelectedOption = item;

InternalValue = Value = value;

//InternalValue = Value = value;
InternalValue = value;
await RaiseChangedEventsAsync();
}
}
Expand All @@ -515,7 +536,10 @@ protected virtual async Task RaiseChangedEventsAsync()
{
if (SelectedOptionsChanged.HasDelegate)
{
await SelectedOptionsChanged.InvokeAsync(_selectedOptions);
if (_selectedOptions.Count != 0)
{
await SelectedOptionsChanged.InvokeAsync(_selectedOptions);
}
}
}
else
Expand All @@ -525,9 +549,6 @@ protected virtual async Task RaiseChangedEventsAsync()
await SelectedOptionChanged.InvokeAsync(SelectedOption);
}
}

// Calling ValueChanged is now done through FluentInputBase.SetCurrentValueAsync
//StateHasChanged();
}

protected virtual async Task OnKeydownHandlerAsync(KeyboardEventArgs e)
Expand All @@ -536,7 +557,10 @@ protected virtual async Task OnKeydownHandlerAsync(KeyboardEventArgs e)
{
return;
}

if (e.ShiftKey == true || e.AltKey == true || e.CtrlKey == true)
{
return;
}
// This delay is needed for WASM to be able to get the updated value of the active descendant.
// Without it, the value sometimes lags behind and you then need two keypresses to move to the next/prev option.
await Task.Delay(1);
Expand Down

0 comments on commit 286b4f1

Please sign in to comment.