Search code examples
c#.netdata-bindingblazor

blazor conditional binding ? can this be simplified?


im building some blazor app and wanted to make wraper around select so it renders items from some casched dictionary values so i have it like

@typeparam T
@inject DictService _dhttp;

@if (this.Label != null)
{
    <MudSelect T="T" @bind-Value="Value" For="@For" Label="@Label" @attributes=AllOtherAttributes>
        @if (Nullable.GetUnderlyingType(typeof(T)) != null)
        {
          <MudSelectItem T="int?" Value="null"> </MudSelectItem>
            @foreach (var item in _dict)
            {
               <MudSelectItem T="int?" Value="item.Key">@item.Value</MudSelectItem>
            }
        }
        else
        {
            @foreach (var item in _dict)
            {
                <MudSelectItem T="int" Value="item.Key">@item.Value</MudSelectItem>
            }
        }
    </MudSelect>
}
else
{
    <MudSelect T="T" @bind-Value="Value" For="@For" @attributes=AllOtherAttributes>
        @if (Nullable.GetUnderlyingType(typeof(T)) != null)
        {
          <MudSelectItem T="int?" Value="null"> </MudSelectItem>
            @foreach (var item in _dict)
            {
               <MudSelectItem T="int?" Value="item.Key">@item.Value</MudSelectItem>
            }
        }
        else
        {
            @foreach (var item in _dict)
            {
                <MudSelectItem T="int" Value="item.Key">@item.Value</MudSelectItem>
            }
        }
    </MudSelect>
}

@code{
 [Parameter]
    public string? Label {get;set;}
....
}

so can this be simplified ? best would be like

 <MudSelect T="T" @bind-Value="Value" For="@For" @if(Label != null){Label="@Label" }@attributes=AllOtherAttributes>

but this not correct for blazor ? (why?)

@if(this.Label != null)
{
    <MudSelect T="T" @bind-Value="Value" For="@For" Label="@Label" @attributes=AllOtherAttributes>
}
else
{
     <MudSelect T="T" @bind-Value="Value" For="@For" Label="@Label" @attributes=AllOtherAttributes>
}
        @if (Nullable.GetUnderlyingType(typeof(T)) != null)
        {...

this is also not correct. why it does not allow this ?? requre all tags inside if to be closed. this is some limitation that i was not aware of....

thanks and regards


Solution

  • Leverage off the @attributes parameter. But, if implemented correctly, you can pass null to the Label parameter, and the component should handle whether it should render or not.

    If the component's implementation does not cater for null, and does something weird, you can add parameters dynamically using the @attributes parameter.

    Example:

    <MudSelect T="T" @bind-Value="Value" For="@For" @attributes="AllOtherAttributes">
    
    @code {
    
    protected override void OnParametersSet()
    {
        AllOtherAttributes = new();
    
        if (AllOtherAttributes.ContainsKey("Label"))
        {
            if (Label == null)
            {
                AllOtherAttributes.Remove("Label"); //Remove Label
            }
            else
            {
                AllOtherAttributes["Label"] = Label; //Update Label
            }
    
        }
        else if (Label != null)
        {
            AllOtherAttributes.Add("Label", Label); //This adds dynamically and works for any Parameter
        }
    }
    

    EDIT:

    Here is another improvement you can make:

    <MudSelect T="T" @bind-Value="Value" For="@For" Label="@Label" @attributes=AllOtherAttributes>
        @if (Nullable.GetUnderlyingType(typeof(T)) != null)
        {
            <MudSelectItem T="T" Value="default" />
        }
        @foreach (var item in _dict)
        {
            <MudSelectItem T="T" Value="item.Key">@item.Value</MudSelectItem>
        }
    </MudSelect>
    

    Simplified, and no need to change the Type for T to int. This will make this component work for any type.