最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

asp.net core - Binding input in a child component in Blazor WASM app - Stack Overflow

programmeradmin5浏览0评论

I'm working on my version of an auto complete component in a Blazor WASM (Standalone) app targeting .NET 9.

I'm able to bind an input to a string variable and take action as user types in his/her search keyword using @bind:after using the following code and it works fine but when I try to move the UI of my auto complete into a component, binding the input to my variable doesn't seem to work. The bind:after part continues to work fine and I hit my method after each keystroke.

Here's the code that works fine which I then move into a component:

...
<input @bind="UserInputText" @bind:event="oninput" @bind:after="OnUserInputChanged" />

...

@code {
   private string? UserInputText = "";

   private void OnUserInputChanged()
   {
      // Process user input and make suggestions
   }
}

I then take the UI part and place it into a new component I'm creating to encapsulate auto-complete into its own component.

Here's the parent code:

...

<AutoComplete UserInputText="UserInput" UserInputTextChangedHandler="OnUserInputChanged" />

...

@code {
   private string? UserInput = "";

   private void OnUserInputChanged()
   {
      // Process user input and make suggestions
   }
}

And here's the code inside the AutoComplete component:

@typeparam TItem

<div>
   <input @bind="UserInputText" @bind:event="oninput" @bind:after="UserInputTextChangedHandler" />
</div>

@code {

   [Parameter]
   public string? UserInputText { get; set; }

   [Parameter]
   public Action UserInputTextChangedHandler { get; set; }

   [Parameter]
   public List<TItem> Suggestions { get; set; }
}

BTW, I tried using EventCallback instead of Action for passing OnUserInputChanged to the auto complete component but then I get an error that states:

Argument 1: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback' to 'System.Action'

Please also keep in mind that wiring the OnUserInputChanged actually continues to work fine even after I place that logic into the new component. The part that no longer works is binding UserInputText to the input inside the component.

Where am I making a mistake?

I'm working on my version of an auto complete component in a Blazor WASM (Standalone) app targeting .NET 9.

I'm able to bind an input to a string variable and take action as user types in his/her search keyword using @bind:after using the following code and it works fine but when I try to move the UI of my auto complete into a component, binding the input to my variable doesn't seem to work. The bind:after part continues to work fine and I hit my method after each keystroke.

Here's the code that works fine which I then move into a component:

...
<input @bind="UserInputText" @bind:event="oninput" @bind:after="OnUserInputChanged" />

...

@code {
   private string? UserInputText = "";

   private void OnUserInputChanged()
   {
      // Process user input and make suggestions
   }
}

I then take the UI part and place it into a new component I'm creating to encapsulate auto-complete into its own component.

Here's the parent code:

...

<AutoComplete UserInputText="UserInput" UserInputTextChangedHandler="OnUserInputChanged" />

...

@code {
   private string? UserInput = "";

   private void OnUserInputChanged()
   {
      // Process user input and make suggestions
   }
}

And here's the code inside the AutoComplete component:

@typeparam TItem

<div>
   <input @bind="UserInputText" @bind:event="oninput" @bind:after="UserInputTextChangedHandler" />
</div>

@code {

   [Parameter]
   public string? UserInputText { get; set; }

   [Parameter]
   public Action UserInputTextChangedHandler { get; set; }

   [Parameter]
   public List<TItem> Suggestions { get; set; }
}

BTW, I tried using EventCallback instead of Action for passing OnUserInputChanged to the auto complete component but then I get an error that states:

Argument 1: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback' to 'System.Action'

Please also keep in mind that wiring the OnUserInputChanged actually continues to work fine even after I place that logic into the new component. The part that no longer works is binding UserInputText to the input inside the component.

Where am I making a mistake?

Share Improve this question edited Mar 30 at 21:46 Sam asked Mar 30 at 21:41 SamSam 30.6k76 gold badges252 silver badges464 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

You should not bind a component Parameter to an input - use a local instead.

The reason is that Blazor keeps a copy of the Component state and will set your Parameter from that state when the Component is going to be rendered. If you bind to that Parameter inside the Component, you have a potential race condition.

So, one possible approach for your code might be to bind the input to a local property which has a getter that returns the Parameter value a setter that updates a local field. You could then pass the local field (i.e. the current value) to your action UserInputTextChangedHandler and allow the parent to update it's state from there.

AutoComplete.razor

@typeparam TItem

<div>
    <input list=suggestions @bind=BindableInputText @bind:event=oninput @bind:after=@(()=>UserInputTextChangedHandler(_currentInputText)) />
    <datalist id=suggestions>
        @foreach (var item in Suggestions ?? [])
        {
            <option>@item</option>
        }
    </datalist>
</div>

@code {
    private string? _currentInputText;
    private string? BindableInputText { get => UserInputText; set => _currentInputText = value; }

    [Parameter]
    public string? UserInputText { get; set; }

    [Parameter]
    public required Action<string?> UserInputTextChangedHandler { get; set; }

    [Parameter]
    public List<TItem>? Suggestions { get; set; } = [];
}

Parent

<AutoComplete UserInputText=@UserInput UserInputTextChangedHandler="OnUserInputChanged" Suggestions=@Suggestions />

<div>Text entered: @UserInput</div>
@code {
    private string? UserInput = "";
    private List<string> Suggestions = [];
    private void OnUserInputChanged(string? UserInputText)
    {
        UserInput = UserInputText;  
        Suggestions = Enumerable.Range(1,5).Select(i=> $"{UserInputText} {i}").ToList();
        StateHasChanged();
    }
}
发布评论

评论列表(0)

  1. 暂无评论