Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Infinite ValueChanged loop in FluentCombobox (Blazor WASM) #3297

Closed
BalKevin opened this issue Feb 4, 2025 · 2 comments · Fixed by #3300 or #3457
Closed

fix: Infinite ValueChanged loop in FluentCombobox (Blazor WASM) #3297

BalKevin opened this issue Feb 4, 2025 · 2 comments · Fixed by #3300 or #3457
Labels
triage New issue. Needs to be looked at

Comments

@BalKevin
Copy link

BalKevin commented Feb 4, 2025

🐛 Bug Report

When trying to handle a custom component based on FluentCombobox, with the update of FluentUI lib version; one of our feature is now KO.
We are trying to force the Combobox to clean its value when the current value is not in the list of available items.

💻 Repro or Code Sample

Here's the code i made to reproduce the issue :

@page "/FluentComboBox"

@using System.Linq.Expressions

<Form Model="modelTest" EnableFluentValidation=true>
    <FluentCombobox
            SelectedOptionChanged="@((selectedOption) => OnSelectedOptionChangedAsync(selectedOption))"
            ValueChanged="@((value) => OnValueChangedAsync(value))"
            ValueExpression="@(() => modelTest.SelectedValue)"
            TOption="OptionItem"
            Items="@Items"
            OptionValue="@(i => i.Value)"
            OptionText="@(i => i.Name)"
            OptionDisabled="@(i => i.Disabled)"
            OptionSelected="@(i => i.Value == modelTest.SelectedValue)"
            Autocomplete=ComboboxAutocomplete.Both
            Placeholder="Testing binding" />

    <p>@modelTest.SelectedValue</p>
</Form>

@code {
    private OptionItem[] Items { get; set; } = [
        new OptionItem { Name = "Test 1", Value = "TEST1", Disabled = false },
        new OptionItem { Name = "Test 2", Value = "TEST2", Disabled = false },
        new OptionItem { Name = "Test 3", Value = "TEST3", Disabled = false }
    ];

    public class ModelTest
    {
        public string? SelectedValue { get; set; }
    }

    private ModelTest modelTest = new();

    private async Task OnSelectedOptionChangedAsync(OptionItem selectedOption)
    {
        Console.WriteLine($"OnSelectedOptionChangedAsync enter modelTest.SelectedValue:{modelTest.SelectedValue}, selectedOption.Value:{selectedOption.Value}.");
        if (modelTest.SelectedValue != selectedOption.Value)
        {
            Console.WriteLine($"OnSelectedOptionChangedAsync before modelTest.SelectedValue:{modelTest.SelectedValue}, selectedOption.Value:{selectedOption.Value}.");
            modelTest.SelectedValue = selectedOption.Value;
            Console.WriteLine($"OnSelectedOptionChangedAsync after modelTest.SelectedValue:{modelTest.SelectedValue}, selectedOption.Value:{selectedOption.Value}.");
        }

        await Task.CompletedTask;
    }

    private async Task OnValueChangedAsync(string? text)
    {
        Console.WriteLine($"OnValueChangedAsync enter modelTest.SelectedValue:{modelTest.SelectedValue}, text:{text}.");
        if (modelTest.SelectedValue != default 
            && (string.IsNullOrEmpty(text) || !Items.Select(i => i.Name).Contains(text)))
        {
            Console.WriteLine($"OnValueChangedAsync before value:{modelTest.SelectedValue}");
            modelTest.SelectedValue = default;
            Console.WriteLine($"OnValueChangedAsync after value:{modelTest.SelectedValue}");
        }

        await Task.CompletedTask;
    }

    public class OptionItem
    {
        public string? Name { get; set; }
        public string? Value { get; set; }
        public bool Hidden { get; set; }
        public bool Disabled { get; set; }
    }
}

To reproduce, you have to select a valid item in the list, let say "Test 2", and then remove the trailing char to let only an invalid value like "Tes", then click outside the field (to lost focus and trigger events)

🤔 Expected Behavior

OnValueChanged (and so ValueChanged event) should only be called once.

😯 Current Behavior

OnValueChanged is going through an infinite loop.
Here's a view of the console logs, linked to the scenario i wrote in the "Repro" section
Image

First 4 logs are the selection of "Test 2", then 2 warning logs we can forget for now, then the 4 lasts when losing focus of the field.

💁 Possible Solution

After multiple tries, either we have to downgrade to an older version of the framework (before a fix on the ValueChanged of this component, it must have a link with this fix). Or find another way to do what i'm trying to achieve ?

🔦 Context

Purpose is to avoid the user to see a "partial" value in the field, either it is filled with a valid item, or not filled at all.
So that he knows directly if the field is ok or not.

🌍 Your Environment

  • OS & Device: Windows on PC
  • Browser: Microsoft Edge
  • .NET and Fluent UI Blazor library Version: Microsoft.NETCore.App in 8.0.12 and Microsoft.FluentUI.AspNetCore.Components in 4.11.3
@microsoft-github-policy-service microsoft-github-policy-service bot added the triage New issue. Needs to be looked at label Feb 4, 2025
vnbaaij added a commit that referenced this issue Feb 4, 2025
ListComponentBase:
- Add a backing field for InternalValue
- Refine checks in OnParameterSet
- Use check on initialized parameters like FluentInputBase

FluentCobobox:
- Use check on initialized parameters like FluentInputBase
- Invoke SelectedOptionChanged if selectedOption is set to null
@vnbaaij
Copy link
Collaborator

vnbaaij commented Feb 5, 2025

@BalKevin Please verify at https://black-pebble-0dc79cb03-3300.westeurope.3.azurestaticapps.net/issue-tester that the issue is resolved.
If so, it will be included in our next patch release (4.11.4). Appreciate if you can do that asap as we are planning to release that version soon.

@BalKevin
Copy link
Author

BalKevin commented Feb 5, 2025

Hello @vnbaaij, i just tried it, it seems to be working just fine !

Congrats for the job done and the short timing :)

Thanks a lot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
triage New issue. Needs to be looked at
Projects
None yet
2 participants