Blazor : how to bind Nullable object to <select>?

Viewed 7096

I want to use a <select> to be able to choose between several values, or choose none.

My component is this one :

<select @bind="SelectedValue">
    <option value="null">Null</option>
    @for (int i = 0; i < 10; i++)
    {
        <option value="@i">Value : @i </option>
    }
</select>

<hr />
    @if (SelectedValue.HasValue)
    {
        <p>The selected value is : @SelectedValue.Value</p>
    }
    else
    {
        <p>the value is null</p>
    }

@code {
    private int? SelectedValue = null;
}

I can bind the <select> value to an int object, but I can't bind the null value. Is there a special syntax I should use, or is it just not supported ?

4 Answers

Why don't you just use -1 instead of null?

<select @bind="SelectedValue">
    <option value="-1">Null</option>
    @for (int i = 0; i < 10; i++)
    {
        <option value="@i">Value : @i </option>
    }
    </select>
<hr />
@if (SelectedValue>-1)
{
    <p>The selected value is : @SelectedValue.Value</p>
}
else
{
    <p>the value is null</p>
}

@code {
    private int? SelectedValue = -1;
}
private string SelectedValue;

private void SelectionChanged(ChangeEventArgs args)
{
    if (args.Value is { })
    {
        SelectedValue = $"The selected value is :{args.Value}";
    }
    else
    {
        SelectedValue = "the value is null";
    }
}
<select @onchange="SelectionChanged">
    <option value="null">Null</option>
    @for (int i = 0; i < 10; i++)
    {
        <option value="@i">Value : @i </option>
    }
</select>

<hr />
<p>@SelectedValue</p>

I created a custom component to bind to nullable ints. Here is the class object:

public class NullableSelect : InputSelect<int?>
{
   protected override bool TryParseValueFromString(string value, out int? result, out string validationErrorMessage)
   {
     if (string.IsNullOrWhiteSpace(value))
       result = null;
     else if (Int32.TryParse(value, out int itemVal))
       result = itemVal;
     else
     {
       validationErrorMessage = "Invalid Value";
       result = null;
       return false;
     }

     validationErrorMessage = null;
     return true;
   }

   protected override string FormatValueAsString(int? value)
   {
     if (!value.HasValue)
       return "";
     else
       return value.Value.ToString();
   }
}

And here's how to use it in a razor file:

<NullableSelect @bind-Value="BoundID" >
  <option value="">(none)</option>
  <option value="1">One</option>
  <option value="2">Two</option>
</NullableSelect>

As a workaround, make a second property to translate.

Also, you can't use an empty string instead of 'null', although you can use a different string. If you use an empty string then the Text property, rather than the Value property is passed as the selected Value.

//On Entity
public int? ProductID { get; set; }

/// <summary>
/// Only used to bind to select
/// </summary>
public string ProductIDAsString
{
    get => ProductID?.ToString()?? "null";
    set => ProductID = value == "null" ? null :(int?)int.Parse(value);
}

//In component
<label>Product</label>
<select @bind="@Model.ProductIDAsString" >
    <option value="null">None</option>
    @foreach (var product in AvailableProducts)
    {
        <option value="@product.ProductID">@product.Label</option>
    }
</select>
Related