Removing dynamically created component always removes last item from list

Viewed 2399

I'm implementing a simple pin-up board with Blazor WebAssembly. When removing any card with the X button, it's always the last element from the list that's removed.

@foreach (var item in _cards)
{
    <div class="card-title">
        <input type="text" id="@item.TitleElementId" value="@item.Title" />
        <button class="btn-remove" @onclick="() => RemoveCard(item)">X</button>
    </div>
}
<button class="btn-add" @onclick="AddNewCard">+</button>

@code {
    private List<Card> _cards = new List<Card>();

    private void AddNewCard()
    {
        _cards.Add(new Card());
    }

    private void RemoveCard(Card card)
    {
        _cards.Remove(card);
        // Also tried _cards.RemoveAll(i => i.TitleElementId == card.TitleElementId);
    }
}
2 Answers

I have noticed it only happens after I modify the value of some of the inputs inside cards.

It turns out to be a problem with value binding. I need to use Blazor's @bind-"" instead of default html value="". Unfortunately I don't know exactly why this happens.

So instead of

<input type="text" value="item.Title"/>

I changed to

<input type="text" @bind="item.Title"/>

and everything works as expected.

Within the for loop, add the @key="item.TitleElementId" attribute using the record unique identifier in order force Blazor to map html control with C# item id.

<input @key="item.TitleElementId" type="text" id="@item.TitleElementId" value="@item.Title" />
<button @key="item.TitleElementId" class="btn-remove" @onclick="() => RemoveCard(item)">X</button>
Related