Вопрос или проблема
У меня есть компонент Input в Blazor. Я хочу вводить только цифры и необязательные десятичные знаки.
И я получаю ошибку: “Unhandled exception rendering component: event.preventDefault is not a function”
-
Компонент должен отображать числа с точками для тысяч.
-
И запятыми для десятичных знаков.
-
Десятичное число должно сохраняться.
@inherits InputNumber<decimal?> @using System.Globalization @using System.Text.RegularExpressions <input @attributes="AdditionalAttributes" id="@_id" class="@CssClass" value="@_stringValue" @onkeydown="OnKeyDown" @oninput="OnInput" @onchange="OnValueChanged" /> <script> window.validateInput = function (inputId, allowDecimals, event) { const key = event.key; if ( (key >= '0' && key <= '9') || key === 'Backspace' || key === 'Tab' || key === 'Enter' || key === 'ArrowLeft' || key === 'ArrowRight' || (allowDecimals && (key === ',' || key === '.')) ) { return true; } event.preventDefault(); return false; } window.formatNumberInput = function (value, allowDecimals) { let cleanedValue = value.replace(/[^0-9.,]/g, ''); let parts = cleanedValue.split(','); let integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, "."); let formattedValue = integerPart; if (allowDecimals && parts.length > 1) { formattedValue += ',' + parts[1].substring(0, 2); } return formattedValue; } </script> @code { private string _id { get; set; } = Guid.NewGuid().ToString(); private string? _stringValue; private string? _currentValue; [Inject] IJSRuntime _jsRuntime { get; set; } [Parameter] public string FormatString { get; set; } = "#,##0.00"; [Parameter] public bool AllowDecimals { get; set; } = true; protected override void OnParametersSet() { if (Value.HasValue) { _stringValue = Value.Value.ToString(FormatString, CultureInfo.CurrentCulture); } else { _stringValue = null; } } private async Task OnKeyDown(KeyboardEventArgs e) { await _jsRuntime.InvokeVoidAsync("validateInput", _id, AllowDecimals, e); } private async Task OnInput(ChangeEventArgs e) { _currentValue = e.Value?.ToString(); var formattedValue = await _jsRuntime.InvokeAsync<string>("formatNumberInput", _currentValue, AllowDecimals); _stringValue = formattedValue; var rawValue = formattedValue.Replace(".", "").Replace(",", "."); if (decimal.TryParse(rawValue, out var result)) { Value = result; await ValueChanged.InvokeAsync(Value); } } private async Task OnValueChanged(ChangeEventArgs e) { await OnInput(e); } }
Ответ или решение
Для обеспечения ввода только чисел (включая не обязательные десятичные) в компоненте Blazor, необходимо правильно настроить поведение ввода, обработку событий и форматирование значения. Ниже приведен полный пример реализации, который решает описанную вами задачу, а также устраняет ошибку "Unhandled exception rendering component: event.preventDefault is not a function".
Пример кода
@inherits InputNumber<decimal?>
@using System.Globalization
@using System.Text.RegularExpressions
<input @attributes="AdditionalAttributes"
id="@_id"
class="@CssClass"
value="@_stringValue"
@onkeydown="OnKeyDown"
@oninput="OnInput"
@onchange="OnValueChanged" />
<script>
window.validateInput = function (inputId, allowDecimals, event) {
const key = event.key;
if (
(key >= '0' && key <= '9') ||
key === 'Backspace' ||
key === 'Tab' ||
key === 'Enter' ||
key === 'ArrowLeft' ||
key === 'ArrowRight' ||
(allowDecimals && (key === ',' || key === '.'))
) {
return true;
}
event.preventDefault();
return false;
}
window.formatNumberInput = function (value, allowDecimals) {
let cleanedValue = value.replace(/[^0-9.,]/g, '');
let parts = cleanedValue.split(',');
let integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ".");
let formattedValue = integerPart;
if (allowDecimals && parts.length > 1) {
formattedValue += ',' + parts[1].substring(0, 2);
}
return formattedValue;
}
</script>
@code {
private string _id { get; set; } = Guid.NewGuid().ToString();
private string? _stringValue;
private string? _currentValue;
[Inject] IJSRuntime _jsRuntime { get; set; }
[Parameter] public string FormatString { get; set; } = "#,##0.00";
[Parameter] public bool AllowDecimals { get; set; } = true;
protected override void OnParametersSet()
{
_stringValue = Value.HasValue ? Value.Value.ToString(FormatString, CultureInfo.CurrentCulture) : null;
}
private async Task OnKeyDown(KeyboardEventArgs e)
{
// Используйте preventDefault только для реальных событий клавиатуры
if (!await _jsRuntime.InvokeAsync<bool>("validateInput", _id, AllowDecimals, e))
{
e.PreventDefault(); // Используйте e.PreventDefault() только если валидация провалилась
}
}
private async Task OnInput(ChangeEventArgs e)
{
_currentValue = e.Value?.ToString();
var formattedValue = await _jsRuntime.InvokeAsync<string>("formatNumberInput", _currentValue, AllowDecimals);
_stringValue = formattedValue;
var rawValue = formattedValue.Replace(".", "").Replace(",", ".");
if (decimal.TryParse(rawValue, out var result))
{
Value = result;
await ValueChanged.InvokeAsync(Value);
}
}
private async Task OnValueChanged(ChangeEventArgs e)
{
await OnInput(e);
}
}
Объяснение решения
-
Валидация ввода: Используется JavaScript для проверки нажатых клавиш через
validateInput
. Это позволяет фильтровать входные данные и разрешить ввод только цифр, а также декодировать символы,
и.
в зависимости от параметраAllowDecimals
. -
Форматирование числа: Функция
formatNumberInput
обрабатывает введённые данные, очищая их от недопустимых символов и форматируя согласно вашему требованию по разделению тысяч с помощью точки и использования запятой в качестве десятичного разделителя. -
Обработка событий: События
onkeydown
,oninput
иonchange
обрабатываются для динамического обновления значения и обеспечения корректного формата. -
Замечание: Проверьте поддержку
IJSRuntime
и убедитесь, что правильно передаете параметры при вызовах из C#. Ошибкаevent.preventDefault is not a function
может быть связана с тем, как передаются события из JavaScript, убедитесь, что используете корректный тип событий.
Следуя этой реализации, вы сможете создать компонент ввода, который будет соответствовать всем указанным требованиям и корректно работать с вводом чисел и десятичных знаков.