This week’s component is an input that only accepts signed integer values. Try as the user might to enter invalid data, such as characters, as soon as they leave the input the value reverts back to the last valid integer.
The InputIntegerBCA component also sports Min and Max parameters to further restrict what the user can enter. If a Min value is not specified then the default value is the greatest negative signed integer value of -231 or -2,147,483,648. If a Max value is not specified then the default value is the maximum positive signed integer value of 231 or 2,147,483,648. If the user enters a value outside the range the input value reverts back to the last valid integer. when the user leaves the input.
Data annotations can also be used with the InputIntegerBCA component. Just apply the Range data annotation to the appropriate property of the model like so.
[Range(1, 50,
ErrorMessage =
"{0} must be in the range of {1} to {2}")]
public int Quantity { get; set; }
Try it for yourself with the BlazorComponentAuthorityDemo
Here’s the markup for InputIntegerBCA.
@namespace BlazorComponentAuthorityLibrary
@inherits InputIntegerBaseBCA
<div class="@ClassDiv">
@if (!string.IsNullOrWhiteSpace(Label))
{
<label class="@ClassLabel"
for="@Id">
@Label
</label>
}
<input @bind-value=@Value
class="form-control @ClassInput @ValidationResultClass"
type="int"
id="@Id"
title="@Title" />
@foreach (var message in ValidationMessages)
{
<h6 class="@ClassValidationMessage"
style="margin-top:3px;">
@message
</h6>
}
</div>
This is the markup for InputIntegerInline which is an inline label version.
@namespace BlazorComponentAuthorityLibrary
@inherits InputIntegerBaseBCA
<div class="@ClassDiv">
<div class="input-group">
<div class="input-group-text @ClassLabel @ValidationResultClass">
@Label
</div>
<input @bind-value=@Value
class="form-control @ClassInput @ValidationResultClass"
type="int"
id="@Id"
title="@Title" />
</div>
@foreach (var message in ValidationMessages)
{
<h6 class="@ClassValidationMessage"
style="margin-top:3px;">
@message
</h6>
}
</div>
Both components inherit the same code from InputIntegerBaseBCA.
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Components;
namespace BlazorComponentAuthorityLibrary
{
public class InputIntegerBaseBCA : InputComponentBase
{
private int originalValue { get; set; }
private int value { get; set; }
/// <summary>
/// The string value of the input
/// </summary>
[Parameter]
public int Value
{
get { return value; }
set
{
if (this.value == value)
{
return;
}
if (Min > value || value > Max)
{
return;
}
this.value = value;
if (ValueChanged.HasDelegate)
{
ValueChanged.InvokeAsync(value);
}
if (OnChanged.HasDelegate)
{
OnChanged.InvokeAsync(value);
}
if (_EditContext != null && For != null)
{
var fieldIdentifier = _EditContext.Field(For);
_EditContext.NotifyFieldChanged(fieldIdentifier);
}
}
}
[Parameter]
public int Max { get; set; } = int.MaxValue;
[Parameter]
public int Min { get; set; } = -int.MaxValue;
/// <summary>
/// A callback method used to update the property bound to the Value parameter.
/// </summary>
[Parameter]
public EventCallback<int> ValueChanged { get; set; }
/// <summary>
/// A callback method that is invoked when the Value changes.
/// </summary>
[Parameter]
public EventCallback<int> OnChanged { get; set; }
protected override void OnInitialized()
{
if (_EditContext != null && !string.IsNullOrWhiteSpace(For))
{
_EditContext.OnFieldChanged += HandleFieldChanged;
_EditContext.OnValidationStateChanged += HandleValidationStateChanged;
}
originalValue = Value;
ValidationResultClass = ClassValid;
base.OnInitialized();
}
private void HandleFieldChanged(object? sender, FieldChangedEventArgs e)
{
GetApplicableValidationMessages();
}
private void HandleValidationStateChanged(object? sender, ValidationStateChangedEventArgs e)
{
GetApplicableValidationMessages();
}
private void GetApplicableValidationMessages()
{
if (_EditContext == null || string.IsNullOrWhiteSpace(For)) { return; }
var fieldIdentifier = _EditContext.Field(For);
var messages = _EditContext.GetValidationMessages(fieldIdentifier).ToList();
if (messages.Count == 0)
{
ValidationMessages.Clear();
var isModified = _EditContext.IsModified(fieldIdentifier);
if (isModified && Value != originalValue)
{
ValidationResultClass = ClassModified;
}
else
{
ValidationResultClass = ClassValid;
}
}
else
{
ValidationResultClass = ClassInvalid;
ValidationMessages = messages;
}
StateHasChanged();
}
private void Dispose()
{
if (_EditContext == null) { return; }
_EditContext.OnFieldChanged -= HandleFieldChanged;
_EditContext.OnValidationStateChanged -= HandleValidationStateChanged;
}
}
}
Which also inherits from InputComponentBase.
public class InputComponentBase : ComponentBase
{
/// <summary>
/// The input Id.
/// Can be used to uniquely identify instances of the component.
/// Helps with making UI testing less brittle.
/// </summary>
[Parameter]
public string Id { get; set; } = string.Empty;
/// <summary>
/// The title or tooltip to show when the user hovers over the input.
/// </summary>
[Parameter]
public string Title { get; set; } = string.Empty;
[CascadingParameter]
protected EditContext? _EditContext { get; set; }
/// <summary>
/// The name of the EditContext model property bound to this input.
/// Required to display the model property validation messages.
/// </summary>
[Parameter]
public string? For { get; set; }
/// <summary>
/// The label to be displayed.
/// </summary>
[Parameter]
public string Label { get; set; } = string.Empty;
/// <summary>
/// The class to be applied to the input element.
/// </summary>
[Parameter]
public string ClassInput { get; set; } = string.Empty;
/// <summary>
/// The class to be applied to the label element.
/// </summary>
[Parameter]
public string ClassLabel { get; set; } = string.Empty;
/// <summary>
/// The class to be applied to the div that wraps the component.
/// </summary>
[Parameter]
public string ClassDiv { get; set; } = string.Empty;
/// <summary>
/// The class to be applied to the input when the input value is valid.
/// </summary>
[Parameter]
public string ClassValid { get; set; } = "valid";
/// <summary>
/// The class to be applied to the input when the input value has been modified.
/// </summary>
[Parameter]
public string ClassModified { get; set; } = "valid modified";
/// <summary>
/// The class to be applied to the input when the input value is invalid.
/// </summary>
[Parameter]
public string ClassInvalid { get; set; } = "invalid";
protected string ValidationResultClass { get; set; } = string.Empty;
/// <summary>
/// The class to be applied to the validation message.
/// </summary>
[Parameter]
public string ClassValidationMessage { get; set; } = "validation-message";
/// <summary>
/// The list of validation messages.
/// </summary>
public List<string> ValidationMessages { get; set; } = new List<string>();
}
}