Search code examples
c#blazormudblazor

Dynamic Controls in MudBlazor/Blazor


I am trying to create dynamic controls in MudBlazor. I am able to do that using Dictionary, as you can see in the code below. The problem I am facing is while removing a control. When Test3 is removed, one control goes away from the display but it looks like the ref for Test4 still points to the Test3 object (please see the screenshot below). Wondering what I am doing wrong over here.

By the way, it works if the last one (Test4) is removed. The problem arises when a control on the top or somewhere in the middle is removed.

NOTE: You can run the code given below in MudBlazor playground (https://try.mudblazor.com/snippet). Once Test3 is removed, and if Test4 text is modified, the new value won't print but Test1 and Test2 will work fine.

@foreach(var value in _newValues)
 {
    
    <MudTextField T="string" Label=@value @ref=_refs[value] />
 }

<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="ButtonOnClick">@ButtonText</MudButton>


<MudGrid>
    @if(_refs.Count>0){
     <MudItem xs="6">
        <MudPaper Class="d-flex align-center justify-left mud-width-full py-8">
            <MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="PrintValues" Class="pa-4">Print Values</MudButton>  
        </MudPaper>
    </MudItem>

    if(@_printValues){
        foreach(var value in _newValues){
                    <MudItem xs="12">
        <MudPaper Class="d-flex align-center justify-left mud-width-full py-8">@_refs[value].Value</MudPaper>
    </MudItem>
        }
     
    }
    
    }
    
    

</MudGrid>





@code {
    

private readonly Dictionary<string, MudTextField<string>> _refs = [];


  private List<string> _newValues = [];

  private bool _printValues = false;

  public string ButtonText { get; set; } = "Remove a TextField";

  //private string _text4Value = string.Empty();


  protected override async Task OnInitializedAsync()
{
     _newValues = new List<string>
  {
    "Test1",
    "Test2",
    "Test3",
    "Test4"
  };;
}

void PrintValues(){
    _printValues = true;
}

void ButtonOnClick()
    {
        
      
                _newValues = new List<string>
            {
            "Test1",
                "Test2",
                "Test4"
            };

        _refs.Remove("Test3");
        ButtonText = "Removed";

         StateHasChanged();
    }


    

}

Screenshot


Solution

  • The renderer is losing track of the component to DOM field mapping. You need to add a key to each iteration like this to help it out:

    @foreach (var value in _newValues)
    {
        <MudTextField T="string" Label=@value @ref=_refs[value] @key="value" />
    }
    

    https://try.mudblazor.com/snippet/mkcSECFRslooYAUF

    enter image description here