microsoft / fluentui-blazor

Microsoft Fluent UI Blazor components library. For use with ASP.NET Core Blazor applications
https://www.fluentui-blazor.net
MIT License
3.78k stars 363 forks source link

FluentSelect loading options from Api call, when return with one entry, can't be selected #1420

Closed alfred-zaki closed 8 months ago

alfred-zaki commented 8 months ago

πŸ› Bug Report

Using FluentSelect and filling options by calling an Api, the Api return with one entry, which is displayed but can't be selected, although the component default to it and visually it's selected but it's never reflected to the @bind-Value even after you try to re-click and re-select it.

πŸ’» Repro or Code Sample

Please note this is a sample code skeleton of my actual code, but not the exact code

@inject IHttpClientFactory _clientFacotry;

@page "/bug"

 <div>
     <FluentSelect @bind-Value="@userRegister.CountryAlpha2Code" Label="Country"
                   Items="countries" OptionText="@(i => i.CountryName)" OptionValue="@(i => i.CountryAlpha2Code)" Required>
     </FluentSelect>
    <p>@userRegister.CountryAlpha2Code</p>
     <FluentValidationMessage For="@(() => userRegister.CountryAlpha2Code)" />
 </div>

@code 
{
private HttpClient apiClient = new HttpClient();

private UserRegister userRegister = new UserRegister();
private List<Country> countries = new List<Country>();

protected override async Task OnInitializedAsync()
{
    try
    {
        apiClient = _clientFacotry.CreateClient("namedClientOnProgram.cs");
        countries = await apiClient.GetFromJsonAsync<List<Country>>($"country/all");
    }
    catch (Exception ex)
    {
    }
}

}

πŸ€” Expected Behavior

either the value should be reflected in userRegister.CountryAlpha2Code OR the list should not default after loading or changing the options and the user should be able to select the entry after loading the options.

please note i am able to select and things work if i returned two entries from the Api call instead of one.

😯 Current Behavior

Can't select this single option no matter what i do.

πŸ’ Possible Solution

I am willing to fix this.

πŸ”¦ Context

provide a user a way to select from a list of values, without allowing any value outside of this list.

🌍 Your Environment

Tested on MAUI windows and android emulator. Microsoft.FluentUI.AspNetCore.Components 4.3.1

vnbaaij commented 8 months ago

Please supply us with a working minimal reproduction. Don't expect us to try andcompose an environment ourselves. We have to many things going on to do this. Help us to help you.

alfred-zaki commented 8 months ago

@vnbaaij please find the code below, this is a home page of a new MAUI project, just added Microsoft.FluentUI.AspNetCore.Components 4.3.1 with all needed code then modified home page to this, the

selectedValue... should be US but a user can't never pick that although the select dose default to it visually. this is not an issue if you have two options but even then the select box default visually to the first value without actually changing bind-value, the value only change if a user a click, with one option not even that is possible.

@page "/"

<FluentSelect @bind-Value="@selectedValue" Label="Test"
            Items="countries" OptionText="@(i => i.CountryName)" OptionValue="@(i => i.CountryAlpha2Code)" Required>
</FluentSelect>
<p>@selectedValue</p>

@code {
    private string selectedValue;
    private List<Country> countries = new List<Country>();

    protected override async Task OnInitializedAsync()
    {
        try
        {
            //Mocking loading the list from API Call
            //await httpClient.GetFromJsonAsync<List<Country>>
            countries.Add(new Country()
            {
                CountryAlpha2Code = "US",
                    CountryName = "United States of America"
            });
        }
        catch (Exception ex)
        {
            //handle errors if any please ignore
        }
    }
}
alfred-zaki commented 8 months ago

country class code if needed

public class Country
{
    public string CountryAlpha2Code { get; set; }
    public string CountryName { get; set; }
}
vnbaaij commented 8 months ago

I can't reproduce the described behavior. Pasted your code in the demo site and ran it:

issue-#1420

It might be something MAUI specific. There have also been some changes in the FluentSelect code for v4.4 so that might have helped to solve this issue. Can you try with the latest package? A select always shows the first option as selected without actually reflecting that in the bound value (before any user interaction)

alfred-zaki commented 8 months ago

@vnbaaij yes i can confirm that upgrading to v4.4 did enable me to select the single value now thanks! still as you screen recording indicate when setting the items on the list, it show the first item as if it was selected, while the binding value do not get updated, i would suggest either set the binding value to match the element visual or even better once a list of items are set the element should still show empty selection reflecting the fact that the user yet to make a selection and that binding value still null.

alfred-zaki commented 8 months ago

here's an example on how this is leading to a confusing user experience, as the list show a value as a user i would expect then that this value is selected, but the truth is it's just the element visual without the binding value being updated so the form still not valid when submitting.

image

thebarrettlo commented 8 months ago

I might be having a similar issue, though it's hard for me to identify if it's just a "me" problem since I'm binding values in a roundabout way (with a Dictionary<T, U> form model rather than a well-defined object). In my case, I have a FluentSelect component that only has one item. I can select the item and confirm that the value takes (as in the example above); however, when submitting the containing form, the field does not seem to be recognized as having been changed and taken the value:

image

Does anyone have insights into whether this behavior for single-value select lists is expected within an EditForm?

vnbaaij commented 8 months ago

@alfred-zaki sorry, but that is just the way the component (and also the underlying web component) works. It doesn't matter if there is only one option or more. See how it works with the standard web component here: https://fluent-components.azurewebsites.net/?path=/docs/components-select--select. The first one is shown, looks selected but isn't THE value selected yet. Nothing we can/want to change here.

vnbaaij commented 8 months ago

@thebarrettlo is should not work differently when there's is only one value. Did you try with the latest version? As @alfred-zaki confirmed already if works with that one

thebarrettlo commented 8 months ago

Apologies, I had that comment written out yesterday but only submitted it today without refreshing the page and seeing @alfred-zaki's update. I am on version 4.4.1, so it must be the way I'm binding values. After looking through the code for FluentSelect and ListComponentBase, I thought that I might be able to trigger a change event for the underlying components using the Blazor OnAfterRender() hook:

private FluentSelect<Enum> _select; // Reference to FluentSelect component using @ref
private IEnumerable<Enum> EnumValues { get; set; }

...

protected override void OnAfterRender(bool firstRender)
{
    if (firstRender && EnumValues.Any())
    {
        _select.SelectedOptionChanged.InvokeAsync(EnumValues.First());
    }
}

Inspecting _select in the debugger shows FluentSelect.InternalValue and FluentSelect.Value updating from null to one of the enum values; but unfortunately, this still doesn't seem to notify the form/component of the state change.

vnbaaij commented 8 months ago

@thebarrettlo maybe better to create a new issue then (with repro code please)? I'm closing this one as @alfred-zaki confirmed it is resolved.