fluentui-blazor
fluentui-blazor copied to clipboard
@bind-Value on FluentCombobox binds to the displayed text, not the value
🐛 Bug Report
FluentCombobox should bind to the value of the selected FluentOption, instead of the displayed part.
💻 Repro or Code Sample
I have a Blazor wasm project. When I make a FluentCombobox, and bind a string using @bind-Value, the contents of the string is set to the diplayed part of the combobox.
@page "/ViewCustomers"
<h1>View Customers</h1>
Selected Value: @selectedCustValue
<FluentCombobox Autocomplete="Autocomplete.List" @bind-Value="selectedCustValue">
@foreach (var cust in customers)
{
<FluentOption Value="@cust.Id.ToString()">@cust.Name</FluentOption>
}
</FluentCombobox>
}
@code {
string selectedCustValue = "";
List<Customer>? customers = new(
new []{new Customer{Id = 0, Name = "abc"}});
}
🤔 Expected Behavior
selectedCustValue should contain the value set in the selected FluentOption ("0" in the example)
😯 Current Behavior
The displayed part of the selected FluentOption is set in SelectedCustValue ("abc" in the example)
🔦 Context
I need the id, since I cannot guarantee that the Name value is unique.
🌍 Your Environment
- OS & Device: Windows 11
- Browser Google Chrome
- .NET and FAST Version .NET 6.0 Microsoft.Fast.Components.FluentUI v. 1.1.0 (LAtest NuGet package)
@radium-v While this issue is coming from the Blazor community, this seems like it could be an issue encountered by others. Any thoughts on how to get the result desired as described above?
For combobox, this is expected behavior:
While
combobox
is implemented in very similar ways asselect
, thevalue
attribute onfast-option
and otheroption
-like elements is ignored in favor of thetextContent
. This is done to avoid confusion between user-provided values and predefined options.
https://github.com/microsoft/fast/blob/master/packages/web-components/fast-foundation/src/combobox/combobox.spec.md
I'm re-reading the issue again and am starting to think I may have misunderstood. @KristianHebert Can you restate the request for us?
I assumed that the bind-Value on a FluentCombobox would bind to the "Value" part of the selected FluentOptions in it. Instead it binds to the text content of the selected option. This is not what is usually needed, since the text may be translated or non-unique (if there are more levels). Maybe there should be more binding options, but i think that bind-Value, should bind to the value.
I can see in the provided link, that it works as designed, which surprises me. I do not understand the explanation, why is this different from an ordinary select? I'll have to use other components.
The documentation is contradictory, since, in the top, it says
value - Reflects the value of the first selected option. Setting the value property will update the selected state of the first option that matches the value, if any.
And in the bottom it says that this is not the case for the combobox.
@radium-v I find this a bit confusing as well. Seems like if you are using combobox for autocomplete but not for accepting any value, there should be a way to have the value bind to the option value. Is this something we can revisit?
I have no idea if this is related, but registering the onchange
event handler causes a new selected option to be reverted. Additionally, if you were to inspect the Value
contained within the ChangeEventArgs
of the handler, it will have the value of the inner text of the FluentOption
not the specified Value
of the FluentOption
. This is problematic if you have back-end logic that is requiring to act on the Value
of the FluentOption when the Combobox value is changed. Currently, there is no way to get this value (that I know of).
Example lifted from your own:
<FluentCombobox id="combobox" Value="Custom Value" @onchange=@((x) => OnComboboxChange(x))>
<FluentOption Value="Please Please Me Foo">Please Please Me</FluentOption>
<FluentOption Value="Custom Value">Yellow Submarine</FluentOption>
<FluentOption>Abbey Road</FluentOption>
<FluentOption>Let It Be</FluentOption>
</FluentCombobox>
@code
{
private void OnComboboxChange(ChangeEventArgs args)
{
var value = args.Value;
}
}
If you remove the @onchange
handler, you will see that the Combobox value changes as expected. If you have the handler in place (ignoring that the value will be oddly reverted), and look at args.Value
, you will see that you don't have, for example, the value of 'Custom Value' if you select 'Yellow Submarine', which makes the Value
of FluentOption
essentially useless.
Note that even if the Value
in the ChangeEventArgs
had to be the contained text of the FluentOption
, a mitigation would be to allow developers to know which FluentOption is actually selected (and thus we could retrieve the property we want). That is, without having to resort to inspecting the DOM to see which fluent-option
has class="selected"
.
@atmgrifter00 With regards to the specification for combobox, this is expected behavior as described in my previous comment. Having separate values for combobox options can conflict with the ability to enter and submit custom values.
A combobox is like a text input with supplementary predetermined options, whereas a select is like a collapsible listbox. In fact, the element internals for combobox use an input
, since unlike select
, there is no native control which reflects the accessibility requirements of a user-editable combobox.
The reason a combobox doesn't use the value
of its options comes down to avoiding the potential for user-defined values that are similar, but different, from any pre-configured values (ex. "fooBAR" vs "FOObar"). While the autocomplete functionality can do a basic job of filtering the list and auto-filling potential matches, there's no way to confirm if a user's input is an incomplete fuzzy search or a specific custom value.
With that said, there are a few useful ways to get the selected items from the DOM:
- Combobox, Select, and Listbox elements all provide the
selectedIndex
andselectedOptions
properties which can be used to determine which item is currently selected. - Option elements have a
selected
boolean property which can be used instead of checking theclass
.
My own personal experience with Blazor is limited, so I don't know if getting the element properties would require hooking it up in this project.
One more alternative would be to use the FluentSelect
component, which doesn't allow for direct user-specified values but does use the values of its selected options for its own. It also supports type-ahead to select the first matching option as you start typing while it's focused.
@radium-v , thanks for the response! From my reading, it still seems that there is no way to do what I want (with the FluentCombobox
...which I prefer its UX to over FluentSelect
) without going into JS-land, which is ultimately something I think the Blazor APIs should attempt to guide you away from. If the FluentCombobox
simply had the selectedIndex
property exposed on it, that would be enough.
@vnbaaij Do you have any availability to look into whether we could connect the selectedIndex up on the FluentCombobox? Seems like it would require custom interop.
Sorry no, interop is not my area of expertise
@radium-v this is not good news for this component.
In enterprise Projects, UX designer is determines what layout to display and we cannot limit them to only one simple text for example:
<FluentOption Value="@item.ID">
<div>
<span class="text">@item.Code</span>
<span class="author">@item.Name</span>
</div>
</FluentOption>
on this sample, the selected value is only the 'Name' property and we cannot find selected item
on the other hands, in some cases, the important properties is more than one property. for example a product have code and name and color and all properties is important for user, and every product is known by all key properties and we cannot use one property to display products list and all key properties are needed for select. for example
product 1 : { id = 1, name : "apple iphone 13" , memory : 512, color : "black" }
product 2 : { id = 2, name : "apple iphone 13" , memory : 512, color : "rose gold" }
product 3 : { id = 3, name : "apple iphone 13" , memory : 1000, color : "black" }
in this example we need to design layout of each Item for simple selection and if we use Select Component, we lose search facility on thousands of Item
from your description, I found that this is only a simple text selector for samples, and we cannot use it on real product if this behavior not changed
I'm redoing the FluentCombobox
, FluentListbox
and FluentSelect
for V2. A (strongly typed) SelectedItem
will be supported there. I also have the Value
working as of now, but that does not reflect a typed in value and I don't think I can get to that typed in value.
I guess it depends on what behavior we expect a combobox to have: 1) an alternative to a select where you can search through the list by typing in the input or 2) a combination (hence the name) of an input and a select list where a use can enter free-form text.
As of the V2.0.0-RC! release, the FluentCombobox
Value parameter represents the selected value from the list or the typed in value of the textbox part.
See the examples in the demo environment: https://brave-cliff-0c0c93310-233.centralus.azurestaticapps.net/Combobox#select-the-best-song-from-the-list-or-type-your-own