【问题标题】:FireFox and selected="selected"FireFox 和 selected="selected"
【发布时间】:2021-09-09 01:58:03
【问题描述】:

注意:我在本文末尾添加了工作示例。在我的 FireFox 中,他们演示了这个问题。任何人都可以在您的 Firefox 中使用我的示例并进行复制。我不知道这是否是工作问题。

我只想让我的 Blazor 解决方案在 Edge 和 FireFox 中工作,但后者在 select 列表中无法正常工作。

41015 years ago 一直在谈论我的问题,但讨论的解决方案并没有解决问题,其他一些Blazor ideas 也没有解决问题。您可以看到尝试修复的一些残余仍然在我的 html 中,例如selectedIndex = "-1",并且所有内容都有一个唯一的名称。

下图是select在渲染显示和浏览器的开发工具中的初始状态。

当我选择第三个或第四个选项时会出现问题 - FireFox 将其翻转回第二个选项。在 Edge 中,它坚持我选择的选项。

Blazor 使用基本循环技术生成 select。 (我也尝试过使用 JSRuntime 设置 selectedIndex)。

<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>

驱动循环的对象具有 IsSelected 属性,该属性使 Blazor 写出 &lt;option selected="selected"&gt; 元素。 @onchange 事件将新选择的选项提交到数据库并运行一堆商业规则。

现在,我将演示这个问题。

使用 Edge,我选择了“完全安装”选项,它表现良好 - select 呈现“完全安装”并且 html 正确地在同一选项上有 selected="selected"

现在我用 FireFox 重复这些步骤。这里又是默认状态。

我再次选择“完全安装”,但现在我们的状态不一致 - select 翻转为“否”,但 html 显示选择了“完全安装”。

无论如何,正确的值都会写入数据库,因此在刷新 FireFox 时会显示正确的选择选项。 Web 开发人员已经忍受了这一点,或者 Mozilla 一直让这个问题陷入困境,这似乎是不可想象的。那我做错了什么?

我拥有的 FireFox 版本是 78.11.0esr(64 位)。

这是一个重现问题的简单示例。

@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},
    };
}

这是一个稍微不同的例子,同样的 FF 问题

@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;
    }
}

【问题讨论】:

  • 邮政编码为文字,而非图片。它应该对 Google 开放。
  • 我用代码替换了代码图片,并提供了一个工作示例。

标签: firefox select blazor selected


【解决方案1】:

由于您没有提供代码,但这里的屏幕截图是一个独立的 Blazor 页面,我相信它封装了您的问题。我错过了你的一些代码位。我还没有测试过它是否会在你的屏幕截图上显示你所有额外的部分,这是有原因的,据我所知它是有效的(引用“正如它在锡上所说的那样”)。

@page "/Select"
<h3>Select</h3>
<div class="form-group col-md-6">
    <label for="dur">Duration</label>
    <select @bind="Duration" class="custom-select">
        <option disabled value="-1" selected>Select an Option</option>
        @foreach (var kvp in SelectData)
        {
            <option value="@kvp.Key">@kvp.Value</option>
        }
    </select>
</div>
<div class="p-2 m-2">
    Current Value : @_Duration
</div>


@code {
    private string _Duration;

    private string Duration
    {
        get => _Duration;
        set
        {
            if (value != _Duration)
            {
                _Duration = value;
            }
        }
    }

    private Dictionary<int, string> SelectData = new Dictionary<int, string>()
    {
        { 11746, "No"},
        { 11747, "Provision Only"},
        { 11748, "Full Installation"}
    };
}

我的 Firefox 是“88.0.1”。 64 位。 Windows 10。

在这个演示中告诉我你的问题在哪里?

这是onchanged 版本:

@page "/Select"
<h3>Select</h3>

<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 kvp in SelectData)
        {
            <option value="@kvp.Key">@kvp.Value</option>
        }
    </select>
</div>
<div class="p-2 m-2">
    Current Key : @_Duration
</div>
<div class="p-2 m-2">
    Current Value : @_DurationValue
</div>


@code {
    private string _Duration;

    private string _DurationValue;

    private string Duration
    {
        get => _Duration;
        set
        {
            if (value != _Duration)
            {
                _Duration = value;
            }
        }
    }

    private void SelectChanged(ChangeEventArgs e)
    {
        _Duration = e.Value.ToString();
        if (int.TryParse(e.Value.ToString(), out int value))
            _DurationValue = SelectData[value];

    }

    private Dictionary<int, string> SelectData = new Dictionary<int, string>()
{
        { 11746, "No"},
        { 11747, "Provision Only"},
        { 11748, "Full Installation"}
    };
}

【讨论】:

  • 我不能使用“@bind”,因为需要“@onchange”
  • 为什么?你没有表现出来。如果不提供一些详细信息,您就不能期待答案,我们不介意读者!
  • 我确实编辑了我的帖子以包含这个“@onchange 事件将新选择的选项提交到数据库并运行一堆商业规则。”
  • 嗨,我在答案中添加了一个 OnChange,它仍然可以正常工作。你需要给我们看一些真实的代码。
  • 我用 Blazor 代码替换了 Blazor 代码图片。现在您的代码像我的一样工作,它将所选选项提交给 onchange。但是,您的代码缺少告诉选择已选择哪个选项的能力。刷新时只显示“选择一个选项”。
【解决方案2】:

这是一个完整的解决方案...复制和粘贴,运行和测试。

@page "/"


@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)
            {
                  <option value="@duration.Name" selected="@duration.IsSelected">@duration.Name</option>
               
            }
        </select>
    </div>

   
}
else
{
    <label>Loading</label>
}

<span class="p-2 m-2">
    Current Value : @_Duration.Name
</span>
<span class="p-2 m-2">
    IsSelected : @_Duration.IsSelected
</span>
<br />
<div>
@foreach (var duration in SelectData)
 {
     <div>@duration.Name: @duration.IsSelected</div>
 }
</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},
        new Duration{ Name = "Hello4", IsSelected = false}
    };
} 

编辑

John Mc, selected="@duration.IsSelected" 不是 Html。这是呈现为空 Html selected 属性或 selected="" 的 Razor 标记,具体取决于所使用的浏览器。这就是在 Blazor 中执行此操作的方法(尽管在当前情况下,您可以仅应用选定的属性而没有值。也就是说,您可以编写:

@if (_Duration == duration)
{ 
  <option value="@duration.Name" selected>@duration.Name</option>
}

),表示selected属性的值由Blazor团队处理,如果评估为true,则添加selectedHtml属性,如果评估为'false',在浏览器中呈现为 Html 之前,它被完全省略了。

您提供的答案是处理 Html 的链接,但这里不是这种情况。上面的@if 语句不是 Html。它是 Razor 标记。 Html 是浏览器呈现的标记。无论如何,至少可以说,答案是有问题的,而且我认为回答者不了解 Html、编码等的基础知识。并不是说我是那个专家……我什至不是开发人员。我已经部分阅读了他的答案,这是我的输入,没有通过代码验证。如果您愿意,您可以自己这样做:

selected Html 属性是一个空属性;也就是说,它的存在指示浏览器选择给定选项。如果不存在,则不进行选择。如果您使用selected="false",则将选择给定的选项。如果您使用selected="Not false",将选择给定的选项。如果您使用selected="Stackoverflow",则将选择给定选项。你明白这个想法吗?验证我是否正确……如果正确,请投票否决答案。

总而言之,根据您真正想做的事情,有很多更好的方法来实现这一点。最重要的是,您应该使用@bind 属性的两种方式数据绑定。您知道您使用的是单向数据绑定吗?

【讨论】:

  • 我不知道 selected 可以接受布尔值,但它有效!另一个对话说这样做是“非标准”和“除了'selected'之外没有任何其他有效值”和“引号内的任何内容都被忽略”等。stackoverflow.com/questions/1033944/…
  • 将 disabled 设置为 bool 也可以。我想接受你的回答,但我不明白它为什么有效。
  • 谢谢。
  • "你从哪里学来的?"来自各种来源,包括 Blazor 的源代码。不,您不会找到任何专门解释这一点的文档,就像您找不到向 Blazor 粉丝解释 WebAssembly Blazor 应用程序中使用的 HttpClient 服务基于 JavaScript Fetch API 的单一来源一样。我怎么知道?我检查了与 HttpClient 对象相关的 C# 代码;我检查了 Blazor 的 JS 代码,我知道 JS,因此得出了明显的结论。当然,您不会在 Blazor 文档中找到它的记录。也许在 Github 的 issue 中,可能会以某种方式被提及……
  • “关于@bind。”我期待这个问题;} 这很容易,但值得提出一个新问题。而且我倾向于相信它没有记录在任何地方,尽管我注意到史蒂夫桑德森的代码是这样的。
【解决方案3】:

如果您使用完全相同的代码生成 Edge 和 FF 标记,那么当您尝试为它们提供字符串值时,看起来这些浏览器对 selecteddisabled 标志的解释不同。

我记得曾几何时必须使用 disabled="disabled" 之类的东西,但 AFAIK 现在的标准只是包含没有价值的标志名称。 我的猜测是您的代码行 &lt;option disabled="" selected=""&gt;Select Answer&lt;/option&gt; 由 Edge 处理得更好,而 FF 处理得更差,但原因是您提供的标记不明确。

您能否从 3 个更改开始,然后告诉我它是否适合您?

  • 删除“SelectedIndex=-1”行,因为它没有任何作用。您将通过@onchange 发送您的价值,以及您的标题选项 无法选择,因为它已被禁用。
  • 将标题行修改为&lt;option disabled selected&gt;Select Answer&lt;/option&gt;
  • 将所有 selected = "selected" 项目更改为 selected 并执行 disabled 也一样。

【讨论】:

  • 我可以做得更好。我在帖子末尾放了一个工作示例,其中包含您要求的更改。它演示了我的 FF 中的问题。
  • 您的新样本将您选择的项目作为参考传递——这意味着当您设置_Duration.IsSelected = true; 时,您也在设置列表中相应项目的选定状态。 Firefox 很困惑,因为您将多个选项设置为 selected,但没有将 &lt;select&gt; 设置为 multiple 标志。
  • 好的,我正在添加一个额外的答案,它在 FF 中运行良好。
【解决方案4】:

以下内容在 FF 中对我来说很好。请注意:

-您不必为标题选项设置 -1 值

-由于您是直接初始化SelectData ,所以它不会为空。

@page "/Select"
<h3>Select</h3>

<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>


<div class="p-2 m-2">
    Current Value : @_Duration.Name
</div>
<div class="p-2 m-2">
    Duration : @_Duration.Value.ToString()
</div>


@code {
    private class Duration
    {
        public string Name { get; set; }
        public TimeSpan Value { get; set; }
    }

    private Duration _Duration = new Duration();


    private void SelectChanged(ChangeEventArgs e)
    {
        _Duration = SelectData.SingleOrDefault(t => t.Name == (string)e.Value);
    }

    private List<Duration> SelectData = new List<Duration>
{
        new Duration{ Name = "Hello1", Value= new TimeSpan(1, 30, 0)},
        new Duration{ Name = "Hello2", Value= new TimeSpan(3, 0, 0)},
        new Duration{ Name = "Hello3", Value= new TimeSpan(10, 0, 0)},
    };

    protected override async Task OnInitializedAsync()
    {
        _Duration = SelectData[2]; // Do your awaitable DB stuff here.
    }
}

【讨论】:

  • 谢谢本尼。请记住,我需要满足两个状态。首先是现有数据可能已经被选择并且选择必须显示它。其次,如果选择更改,则必须在 onchange 中设置 IsSelected,然后由一堆业务逻辑使用。据我所知,(不使用@bind)显示第一种情况的唯一方法是合并 IsSelected,如我所示。您的示例不会显示预先存在的选定答案。
  • 除非您想选择多个项目,否则您不应该这样做。在您的数据加载器中,您应该确定选择了哪个项目,并将 _Duration 设置为该项目,然后使用它来确定要选择的项目。我将更新此答案以表明这一点。
  • 有趣的是,Edge 并不介意我当前的代码。
  • 好的,更新答案以显示预选数据。你是对的,这很有趣。每个浏览器开发人员都必须对诸如selected="" 之类的边缘条件做出选择是否应该只输出selected,因为无论如何您都不需要该标志的字符串?它是否应该决定你有充分的理由添加一个空字符串,比如你稍后会用它做一些 JavaScript 诡计,并输出它,即使它格式错误?它是否应该评估为假,因为它不是一个允许的选项?这就是浏览器可能采取不同行动的边缘情况。
  • 我对您的示例进行了一些调整,以管理“后端”的 IsSelected 标志,使您的渲染逻辑保持原样。我将把它粘贴到我之前的例子中。唉,FireFox 问题依然存在。
猜你喜欢
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 2013-05-16
  • 2011-02-27
  • 2015-05-31
  • 1970-01-01
  • 2019-04-09
  • 2012-03-14
相关资源
最近更新 更多