NOTE: I added working examples at the end of this post. In my FireFox, they demonstrate the problem. CAN ANYONE TAKE MY EXAMPLES AND REPRO IN YOUR FIREFOX. I have no way of knowing if this is a work problem or not.
All I want is for my Blazor solution to work in Edge and FireFox, but the latter is not working as expected with a select list.
The issue I have has been talked about again and again 4, 10 and 15 years ago yet the solutions discussed are not solving the problem nor are some other Blazor ideas. You can see some of the remnants of the attempted fixes are still in my html, such as selectedIndex = "-1"
and everything has a unique name.
The below picture is the initial state of the select in the rendered display and the browser's dev tools.
The issue happens when I pick the third or fourth option - FireFox flips it back to the second option. In Edge it sticks to the option I picked.
Blazor generates the select using a basic loop technique. (I've also tried setting the selectedIndex using JSRuntime).
<select name="@QuestionItem.Id" style="width: 218px; height:34px;" TValue="Answer" @onchange="SelectChanged">
<option disabled="" selected="">Select Answer</option>
@foreach (var a in QuestionItem.Answers)
{
// maybe https://stackoverflow.com/questions/60599131/blazor-select-dropdown-set-active-value-by-code
@if (a.IsDisqualified)
{
<option disabled="disabled" value="@a.Id">@a.Name</option>
}
else
{
@if (a.IsSelected)
{
<option name="@a.Id" value="@a.Id" selected="selected">@a.Name</option>
}
else
{
<option name="@a.Id" value="@a.Id">@a.Name</option>
}
}
}
</select>
The objects that drive the loop have an IsSelected property that has Blazor write out an <option selected="selected">
element. The @onchange event commits the newly picked option to the database and runs a bunch of biz rules.
Now, I'll demonstrate the problem.
Using Edge, I pick the "Full Installation" option and it behaves fine - the select renders "Full Installation" and the html properly has selected="selected"
on the same option.
Now I repeat those steps with FireFox. Here again is the default state.
Once again I choose "Full Installation" but now we get an inconsistent state - the select flips to "No" but the html shows "Full Installation" is selected.
Regardless, the correct value is written to the database so upon refresh FireFox then shows the correct selected option. It seems inconceivable that web developers have put up with this or that Mozilla has left the problem languishing all this time. So what am I doing wrong?
The version of FireFox I have is 78.11.0esr (64-bit).
Here is a simple example that reproduces the problem.
@page "/Select"
<h3>Select</h3>
@if (SelectData != null)
{
<div class="form-group col-md-6">
<label for="dur">Duration</label>
<select class="custom-select" @onchange="this.SelectChanged">
<option disabled value="-1" selected>Select an Option</option>
@foreach (var duration in SelectData)
{
@if (duration.IsSelected)
{
<option value="@duration.Name" selected>@duration.Name</option>
}
else
{
<option value="@duration.Name">@duration.Name</option>
}
}
</select>
</div>
}
else
{
<label>Loading</label>
}
<div class="p-2 m-2">
Current Value : @_Duration.Name
</div>
<div class="p-2 m-2">
IsSelected : @_Duration.IsSelected
</div>
@code {
private class Duration
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
private Duration _Duration = new Duration();
private void SelectChanged(ChangeEventArgs e)
{
var selected = SelectData.SingleOrDefault(t => t.Name == (string)e.Value);
if (selected != null)
{
_Duration = selected;
_Duration.IsSelected = true;
}
}
private List<Duration> SelectData = new List<Duration>
{
new Duration{ Name = "Hello1", IsSelected = false},
new Duration{ Name = "Hello2", IsSelected = false},
new Duration{ Name = "Hello3", IsSelected = false},
};
}
Here is a slightly different example with the same FF problem
@page "/Select"
<h3>Select</h3>
@if (SelectData != null)
{
<div class="form-group col-md-6">
<label for="dur">Duration</label>
<select class="custom-select" @onchange="this.SelectChanged">
<option disabled selected>Select an Option</option>
@foreach (var duration in SelectData)
{
@if (_Duration == duration)
{
<option value="@duration.Name" selected>@duration.Name</option>
}
else
{
<option value="@duration.Name">@duration.Name</option>
}
}
</select>
</div>
}
else
{
<label>Loading</label>
}
<div class="p-2 m-2">
Current Value : @_Duration.Name
</div>
<div class="p-2 m-2">
IsSelected : @_Duration.IsSelected
</div>
@code {
private class Duration
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
private Duration _Duration = new Duration();
private void SelectChanged(ChangeEventArgs e)
{
var selected = SelectData.SingleOrDefault(t => t.Name == (string)e.Value);
if (selected != null)
{
_Duration = selected;
_Duration.IsSelected = true;
}
}
private List<Duration> SelectData = new List<Duration>
{
new Duration{ Name = "Hello1", IsSelected = false},
new Duration{ Name = "Hello2", IsSelected = false},
new Duration{ Name = "Hello3", IsSelected = false},
};
protected override async Task OnInitializedAsync()
{
var a = SelectData.FirstOrDefault(t => t.IsSelected);
if (a != null)
_Duration = a;
}
}