this is my first time with Blazor, so apologies if this sounds stupid. Here is some Blazor code I wrote:
<ul>
@foreach (var tag in tags)
{
<li>
@tag
<button class="btn btn-primary" @onclick="() => remove(tag)">remove</button>
</li>
}
</ul>
<PageTitle>Home</PageTitle>
<h1>Tags</h1>
<input placeholder="Enter tag" @bind=@tag @onkeydown="enter"/>
<button class="btn btn-primary" @onclick="addTag">Add</button>
<button class="btn btn-primary" @onclick="clear">Clear</button>
@code {
private string tag;
private List<string> tags = new List<string>();
private void addTag()
{
if (tags.Count() < 5)
{
tags.Add(tag);
tag = string.Empty;
}
}
private void enter(KeyboardEventArgs e)
{
if (e.Code == "Enter")
{
addTag();
}
}
private void clear()
{
tags.Clear();
}
private void remove(string tag)
{
tags.Remove(tag);
}
}
For some reason that I cannot figure out, I expected that both when the Add button is clicked, or the enter key is pressed, the behavior should be the same, i.e, the input entered in the text box will get stored in @tag, and added to the tags list. This is indeed what happens when the add button is clicked, but when the Enter key is pressed, the first tag in the list of tags is always an empty string, and then on, it is off by one. So for example:
If I put mango in the input box and hit enter, the first <li>
item to pop up on my screen is "".
If I then put apple in the input box and hit enter, the next <li>
item to pop up on my screen is mango.
It is off by one, and for the life of me, I cannot figure out why.
2
Answers
The problem is by default the
@bind
attribute updates the value when thechange
event is fired on the input control. When you press enter the input box, theonkeydown
event will be fired before thechange
event, so the value of thetag
field doesn’t change. To keep the value up-to-date you can do:You can also try
keyup
event, because it is fired after thechange
event:ASP.NET Core Blazor data binding
Your problem happens because of the order in which the events execute.
If you add the following code you will see that
tag
is being set.In your current setup:
onchanged
event (wired up by the @bind.)tag
when either the input loses focus (you click somewhere else) or your click Enter.However the
onkeydown
event occurs when you press enter i.e. before theonchanged
event. At this pointtag
contains the old value, it hasn’t been updated yet.You can change the event sequence by manually wiring up the input and triggering
tag
updates on theoninput
event rather that ononchange
. Note I’ve also movedOnEnter
to theonkeyup
event to ensure it’s called last (you can never be sure of how differtent browsers implement these events).Here’s your input:
Version 1 – Net6.0 or earlier
Version 2 – Net7.0
And the UI event handlers.
The events now trigger in the correct order.
Here’s my full demo page: