【问题标题】:How to get two-way binding in Blazor with a SELECT Component?如何在 Blazor 中使用 SELECT 组件进行双向绑定?
【发布时间】:2020-02-14 01:02:50
【问题描述】:

我正在尝试编写一个使用 <select...>Blazor 组件,以更新从父级传入的变量。

我想点击下拉菜单(选择/选项),选择一个选项,然后让它自动更新父项中的变量。

如果我不使用组件,我可以让它工作。但是我可以让它从组件中工作的唯一方法是,如果我还在组件中使用一个按钮(请参阅组件代码中的按钮)。但最终会有几个组件从同一个父级调用。为每个组件设置一个单独的按钮是不切实际的。所以按钮必须消失。

@bind 使用“onchange”参数进行选择,因此甚至无法编译。

我尝试过 CascadingValue/CascadingParam 但这也不会更新父值(除非我使用按钮...)

这是父级:

@page "/test"
@page "/test/{param}"

@namespace ComponentTest.Pages

@using System.Web
@using ComponentTest.Pages

<h3>Test Page</h3>

<div class="border col-3">
    <h4>Parent</h4>
    <hr />
    <label for="parentValue">Parent Value</label>
    <input id="parentValue" @bind="@param"/>
</div>
<div class="col-3">&nbsp</div>
<div class="border col-3">
    <h4>Component Select</h4>
    <hr />
    <SelectComponent @bind-Item="@param"/>
</div>

@code {
    [Parameter]
    public string param { get; set; }
}

这是组件:

@using System.Collections.Generic
@using System.Web

<div class="form-group">
    <p>Component Value = @Item</p>
    <label for="Site" class="font-weight-bold form-check-label">List</label>
    @if (list == null)
    {
        <input id="Item" class="form-control-sm" @bind="@Item" />
    }
    else
    {
        <select id="Item" class="form-control-sm" @bind="@Item">
            @foreach (var l in list)
            {
                @if (Item != null && String.Equals(l, Item, StringComparison.OrdinalIgnoreCase))
                {
                    <option selected value="@l">@l</option>
                }
                else
                {
                    <option value="@l">@l</option>
                }
            }
        </select>
    }
</div>
<button @onclick="UpdateParentsItem" class="btn btn-primary">Update Parent</button>
@code {
    public IEnumerable<string> list = new List<string>()
{
        "Item 1",
        "Item 2",
        "Item 3",
        "Item 4",
        "Item 5"
    };

    [Parameter]
    public string Item { get; set; }

    [Parameter]
    public EventCallback<string> ItemChanged { get; set; }

    private async Task UpdateParentsItem()
    {
        await ItemChanged.InvokeAsync(Item);
    }
}

我遵循了一些实现事件的常规示例,但我发现没有一个能真正解决问题。

【问题讨论】:

    标签: c# html-select blazor blazor-server-side


    【解决方案1】:

    此代码 sn-p 正在运行。试试看... 运行代码并开始输入单词Item 3。当您键入时,您将看到子组件和父组件显示的类型文本。当您完成第 3 项的键入时,您会注意到文本 Item 3 显示在组合框中。从组合框中选择一个项目,它会出现在父级的输入框中。

    SelectComponent.razor

        <div style="border:solid 1px red">
         <select id="Item" class="form-control-sm" @bind="@Item">
            @foreach (var l in list)
            {
                @if (Item != null && String.Equals(l, Item, 
                 StringComparison.OrdinalIgnoreCase))
                {
                    <option selected value="@l">@l</option>
                }
                else
                {
                    <option value="@l">@l</option>
                }
            }
        </select>
    
     </div>
     <p>@Item</p>
    
     @code {
      public IEnumerable<string> list = new List<string>()
     {
        "Item 1",
        "Item 2",
        "Item 3",
        "Item 4",
        "Item 5"
     };
    
    
     private string item { get; set; } 
    
     [Parameter]
     public string Item
     {
        get { return item; }
        set
        {
            if (item != value)
            {
                item = value;
                if (ItemChanged.HasDelegate)
                {
                    ItemChanged.InvokeAsync(value);
                }
            }
        }
      }
    
     [Parameter]
     public EventCallback<string> ItemChanged { get; set; }
     }
    

    Test.razor

    @page "/test"
    
    <div>
    
    <label for="parentValue">Parent Value</label>
    
    <input type="text" id="parentValue" @bind="@Param" 
         @bind:event="oninput" />
    
    <p>@Param</p>
    </div>
    
    <div>
    
    <SelectComponent @bind-Item="@Param"/>
    </div>
    
    @code {
      [Parameter]
    public string Param { get; set; } = string.Empty;
    
    }
    

    祝你好运...如果有不清楚的地方,请不要犹豫...

    【讨论】:

    • 完美,谢谢。我所做的唯一更改是删除“@bind:event”——没有必要。默认(onchange?)完全按照我的要求工作。
    【解决方案2】:

    我将答案归功于@enet,但这是我的完整解决方案,其中包括他(她?)位,并进行了额外的验证检查:

    Test.razor(父级)

    @page "/test"
    @page "/test/{param}"
    
    <h3>Select Component Test</h3>
    
    <div class="border col-2">
        <h4>Parent</h4>
        <hr />
        <div class="form-group">
            <label for="parentValue">Parent Value</label>
            <input id="parentValue" type="text" class="form-control" @bind="@param" />
        </div>
    </div>
    <div class="col-3">&nbsp</div>
    <div class="border col-2">
        <h4>Component</h4>
        <hr />
        <SelectComponent @bind-Item="@param" />
    </div>
    <hr />
    <ul>Links
        <li><a href="/test/item 1">item 1</a></li>
        <li><a href="/test/ITEM 2">ITEM 2</a></li>
        <li><a href="/test/iTeM 3">iTeM 3</a></li>
        <li><a href="/test/ItEm 4">ItEm 4</a></li>
        <li><a href="/test/item 99">item 99</a></li>
    </ul>
    @code
    {
        [Parameter]
        public string param { get; set; }
    }
    

    SelectComponent.razor

    <!-- Select Component -->
    <div class="form-group">
        @if (message != null)
        {
            <p class="text-warning">@message</p>
        }
        <label for="Item" class="form-check-label">Item</label>
        @if (list == null)
        {
            <input id="Item" class="form-control-sm" @bind="@Item" />
        }
        else
        {
            <select id="Item" class="form-control-sm" @bind="@Item">
                @foreach (var l in list)
                {
                    <option value="@l">@l</option>
                }
            </select>
        }
    </div>
    @code {
        private string message;
    
        public IEnumerable<string> list = new List<string>()
        {
            "Item 1",
            "Item 2",
            "Item 3",
            "Item 4",
            "Item 5"
        };
    
        private string item { get; set; }
    
        [Parameter]
        public string Item
        {
            get { return item; }
            set
            {
                if (item != value)  // skip if it's the same string
                {
                    if (list == null || list.Count() == 0)
                    {
                        item = value;
                    }
                    else
                    {
                        // validate the new item value against my list
                        foreach (var l in list)
                        {
                            if (value != null && String.Equals(l, value, StringComparison.OrdinalIgnoreCase))
                            {
                                item = l;   // match exact case to my list so "selected" option works properly
                                message = null;
                            }
                        }
    
                        // if there's no match, clear the item
                        if (!String.Equals(item, value, StringComparison.OrdinalIgnoreCase))
                        {
                            item = null;
                            message = "Invalid Item";
                        }
                    }
    
                    // make sure there is a parent
                    if (ItemChanged.HasDelegate)
                    {
                        // this is the magic that updates the parent
                        ItemChanged.InvokeAsync(item);
                    }
                }
            }
        }
    
        [Parameter]
        public EventCallback<string> ItemChanged { get; set; }
    }
    

    我将把它用作几个基于实体框架的表单验证下拉菜单的模板。

    【讨论】:

      猜你喜欢
      • 2020-01-15
      • 1970-01-01
      • 1970-01-01
      • 2019-10-01
      • 2020-10-09
      • 2022-07-20
      • 2023-01-11
      • 2020-03-26
      • 2022-11-07
      相关资源
      最近更新 更多