I'm creating a form in Blazor and I like to have a segment like the following example
Using Bootstrap, I have this code for that
<div class="btn-group" role="group" aria-label="Basic radio toggle button group">
<input type="radio" id="btnradio1-@Id" class="btn-check" name="btnradio1-@Id"
autocomplete="off" checked @bind-value="Value">
<label class="form-label btn btn-outline-primary" for="btnradio1-@Id">
Yes</label>
<input type="radio" id="btnradio2-@Id" class="btn-check" name="btnradio2-@Id"
autocomplete="off" @bind-value="Value">
<label class="form-label btn btn-outline-primary" for="btnradio2-@Id">
No</label>
<input type="radio" id="btnradio3-@Id" class="btn-check" name="btnradio3-@Id"
autocomplete="off" @bind-value="Value">
<label class="form-label btn btn-outline-primary" for="btnradio3-@Id">
Sometimes</label>
</div>
and in the code, I have this parameter:
[Parameter] public string Id { get; set; } = Guid.NewGuid().ToString();
[Parameter] public string? Value { get; set; }
When I click on an input, I want to change the Value with the correspond value of the input I clicked. For example, if I click on No, I want that the Value is No.
Using html radio buttons to do this is a little problematic. I've found it easier to build a custom InputBase
component using the Bootstrap ButtonGroup with normal buttons.
Here's a simple version:
@using System.Diagnostics.CodeAnalysis
@inherits InputBase<string>
<div class="btn-group mt-1 me-2 mb-3" data-toggle="buttons">
@foreach( var item in this.Options)
{
<button type="button" class="@this.GetButtonCSS(item.Value)" @onclick="() => ValueHasChanged(item.Value)">
@item.Value
</button>
}
</div>
@code {
[Parameter, EditorRequired] public IEnumerable<SelectOption<string>> Options { get; set; } = Enumerable.Empty<SelectOption<string>>();
[Parameter] public string SelectedCss { get; set; } = "btn btn-primary";
[Parameter] public string UnSelectedCss { get; set; } = "btn btn-outline-primary";
protected override bool TryParseValueFromString(string? value, out string result, [NotNullWhen(false)] out string? validationErrorMessage)
{
result = value ?? string.Empty;
validationErrorMessage = null;
return true;
}
private string GetButtonCSS(string value)
{
return value.Equals(this.Value)
? this.SelectedCss
: this.UnSelectedCss;
}
private void ValueHasChanged(string value)
{
this.CurrentValueAsString = value;
}
}
The option object:
public readonly record struct SelectOption<TValue>(TValue Value, string Label);
And a demo page:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<EditForm Model="_model">
<RadioButtonInput Options="_options" @bind-Value="_model.Value1" />
<RadioButtonInput Options="_options" @bind-Value="_model.Value2" />
<RadioButtonInput Options="_options" @bind-Value="_model.Value3" />
</EditForm>
<div class="bg-dark text-white m-2 p-2">
<pre>Value1: @_model.Value1</pre>
<pre>Value2: @_model.Value2</pre>
<pre>Value3: @_model.Value3</pre>
</div>
@code {
private List<SelectOption<string>> _options = new() {
new("Yes", "Yes"),
new("No", "No"),
new("Sometimes", "Sometimes")
};
private Model _model = new();
public class Model
{
public string Value1 { get; set; } = "N";
public string Value2 { get; set; } = "N";
public string Value3 { get; set; } = "N";
}
}