glacasa
glacasa

Reputation: 1896

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

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 ?

Upvotes: 13

Views: 15281

Answers (5)

Dimitri Sluzki
Dimitri Sluzki

Reputation: 71

Who works with the MudBlazor (MudSelector) could use this:

public class NullMudselect : MudSelect<int?>
{
    int itemVal;

    protected override Task SetValueAsync(int? value, bool updateText = true)
    {
        if (value == null)
            return base.SetValueAsync(null, updateText);
        else
        {
            if (Int32.TryParse(value.ToString(), out itemVal))
                return base.SetValueAsync(itemVal, updateText);
            else
                return null;
        }
    }

    protected override Task SetTextAsync(string text, bool updateValue = true)
    {
        try
        {
            if (string.IsNullOrEmpty(text) || string.IsNullOrWhiteSpace(text))
                return base.SetTextAsync(null, updateValue);
            else if (Int32.TryParse(text, out itemVal))
                return base.SetTextAsync(text, updateValue);
            else
            {
                return base.SetTextAsync(null, updateValue);
            }
        }
        catch (Exception ex)
        {
            return base.SetTextAsync(null, updateValue);
        }
    }
}

End usage:

<Column T="T" Field="MyField" Title="MyTitle">
    <EditTemplate>
       <NullMudselect @bind-Value="context.Item.staff_sick_days_typesysid" Margin="@Margin.Dense">
       <MudSelectItem Value="@(new int?())">Please select</MudSelectItem>
         @for (int r = 0; r < data_source.Rows.Count; r++)
         { 
            var value_member = data_source.Rows[r]["sysid"] == null || data_source.Rows[r]["sysid"] == DBNull.Value ? new int?() : Convert.ToInt32(data_source.Rows[r]["sysid"]);
            var dislsplay_member = data_source.Rows[r]["description"] == null || data_source.Rows[r]["description"] == DBNull.Value ?
             string.Empty : data_source.Rows[r]["description"].ToString();
              <MudSelectItem Value="@value_member">@dislsplay_member</MudSelectItem>
       }
      </NullMudselect></EditTemplate></Column>

Upvotes: 3

Rono
Rono

Reputation: 3361

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>

Upvotes: 5

Joseph Piotti
Joseph Piotti

Reputation: 1

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>

Upvotes: -1

Zsolt Bendes
Zsolt Bendes

Reputation: 2579

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>

Upvotes: 1

Altosh
Altosh

Reputation: 62

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;
}

Upvotes: 2

Related Questions