Search code examples
c#blazormudblazor

MudRadioGroup not selecting the correct MudRadio when a MudRadio is removed


<MudRadioGroup T="string" SelectedOption="@selectedItem" SelectedOptionChanged="OnSelectedOptionChanged">
    @foreach (var item in Items)
    {
        <div>
            <MudRadio Option="@(item)" Color="Color.Primary">@item</MudRadio>
            <MudButton OnClick="() => RemoveItem(item)" Variant="Variant.Filled">Remove</MudButton>
        </div>
    }
</MudRadioGroup>


@code {
    private string selectedItem = string.Empty;

    private List<string> Items = new()
    {
        "Item1",
        "Item2",
        "Item3"
    };

    private void OnSelectedOptionChanged(string selectedOption)
    {
        selectedItem = selectedOption;
    }

    private void RemoveItem(string item)
    {
        Items.Remove(item);
    }
}

I have created a snippet here.

How can I change this so that when items are removed the selected radio is updated in the UI? Currently if I select Item2 and then remove Item1, Item2 and Item3 correctly remain, however Item3 is selected instead of Item2.

It's as if the index is all the MudRadioGroup cares about and it doesn't shift the index to the correct item.

I have tried calling StateHasChanged at the end of both OnSelectedOptionChanged and RemoveItem, but this has no effect.


Solution

  • This issue you're facing can be solved using the @key attribute.

    From Ms Docs

    When rendering a list of elements or components and the elements or components subsequently change, Blazor must decide which of the previous elements or components are retained and how model objects should map to them. Normally, this process is automatic and sufficient for general rendering, but there are often cases where controlling the process using the @key directive attribute is required.

    We add the @key to the parent element of the loop item, which in your case is the <div>.

    <MudRadioGroup T="string" SelectedOption="@selectedItem" SelectedOptionChanged="OnSelectedOptionChanged">
        @foreach (var item in Items)
        {
            <div @key="item">
                <MudRadio Option="@(item)" Color="Color.Primary">@item</MudRadio>
                <MudButton OnClick="() => RemoveItem(item)" Variant="Variant.Filled">Remove</MudButton>
            </div>
        }
    </MudRadioGroup>
    

    Also your RemoveItem method should also handle un-assigning the selectedItem in the case when the selectedItem is removed.

    private void RemoveItem(string item)
    {
        if(selectedItem == item){
            selectedItem = string.Empty;
        }
        Items.Remove(item);
    }
    

    MudBlazor Snippet