Number Input - mousewheeel fix, prevent of enetering flase characters

pull/7/head
stm 2 years ago
parent ed15c8f24d
commit 1fd0028557

@ -5,18 +5,18 @@
@typeparam NumberType @typeparam NumberType
<div class="@InputFieldClassList"> <div class="@InputFieldClassList">
<input type="number" <input type="text"
placeholder="@Placeholder" placeholder="@Placeholder"
step="@_step" step="@_step"
disabled="@Disabled" disabled="@Disabled"
readonly="@Readonly" readonly="@Readonly"
@onmousewheel="@OnMouseWheel" @onkeydown=@(args => ChangeValue(args))
@onwheel="@OnMouseWheel" @onkeydown:preventDefault="@_preventDefaultAction"
@oninput=@ChangeValueAsync @oninput=@GetValueAsync
@bind-value="@Value" @onmousewheel=@OnMouseWheel
@attributes="@InputAttributes"> @onwheel="OnMouseWheel"
</input> @bind-value="@_value"
@attributes="@InputAttributes" />
<span class="highlight"></span> <span class="highlight"></span>
<span class="bar"></span> <span class="bar"></span>
@ -34,6 +34,10 @@
} }
<span class="input-glyph-wraper"> <span class="input-glyph-wraper">
<span class="input-glyph"> <span class="input-glyph">
<span style="display:inline-block">
<Glyph Width=16 Height=16 SVG="@Icons.Material.Outlined.KeyboardArrowUp" Click="StepUp" />
<Glyph Width=16 Height=16 SVG="@Icons.Material.Outlined.KeyboardArrowDown" Click="StepDown"></Glyph>
</span>
@if (Clearable && Value.ToString().Length > 0) @if (Clearable && Value.ToString().Length > 0)
{ {
<span class="input-glyph button" @onclick="Clear"> <span class="input-glyph button" @onclick="Clear">

@ -3,11 +3,11 @@ using Connected.Utilities;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
using System.Numerics; using System.Numerics;
using static Connected.Colors;
namespace Connected.Components; namespace Connected.Components;
public partial class NumberInput<NumberType>:InputBase where NumberType : INumber<NumberType> public partial class NumberInput<NumberType>:InputBase where NumberType : INumber<NumberType>
{ {
private double _step =1; private double _step =1;
[Parameter] [Parameter]
public double Step { public double Step {
@ -22,30 +22,56 @@ public partial class NumberInput<NumberType>:InputBase where NumberType : INumbe
} }
[Parameter] [Parameter]
public bool DisableMouseWheel { get; set; } = false; public bool DisableMouseWheel
{
get;
set;
} = false;
private async Task StepUp() private async Task StepUp()
{ {
double num = (double)Convert.ChangeType(Value, typeof(double)); try
num += _step; {
Value = AdjustDecimalPlaces((NumberType)Convert.ChangeType(num, typeof(NumberType))); double num = (double)Convert.ChangeType(Value, typeof(double));
num += _step;
if (DecimalPlaces > 0)
num = Math.Round(num, DecimalPlaces);
Value = (NumberType)Convert.ChangeType(num, typeof(NumberType));
if (IsError) ErrorText = string.Empty;
}
catch
{
ErrorText = "Error with step up!";
Value = default(NumberType);
}
await ValueChanged.InvokeAsync(Value); await ValueChanged.InvokeAsync(Value);
} }
private async Task StepDown() private async Task StepDown()
{ {
double num = (double)Convert.ChangeType(Value, typeof(double)); try
num -= _step; {
Value = AdjustDecimalPlaces((NumberType)Convert.ChangeType(num, typeof(NumberType))); double num = (double)Convert.ChangeType(Value, typeof(double));
num -= _step;
if (DecimalPlaces > 0)
num = Math.Round(num, DecimalPlaces);
Value = (NumberType)Convert.ChangeType(num, typeof(NumberType));
if (IsError) ErrorText = string.Empty;
} catch
{
ErrorText = "Error with step down!";
Value = default(NumberType);
}
await ValueChanged.InvokeAsync(Value); await ValueChanged.InvokeAsync(Value);
} }
protected async Task OnMouseWheel(WheelEventArgs obj) protected async Task OnMouseWheel(WheelEventArgs args)
{ {
if (DisableMouseWheel==false) if (DisableMouseWheel == false)
{ {
if (!obj.ShiftKey || Disabled || Readonly) if (args.ShiftKey || Disabled || Readonly)
return; return;
if (obj.DeltaY < 0) if (args.DeltaY >= 0)
{ {
await StepDown(); await StepDown();
} }
@ -53,69 +79,136 @@ public partial class NumberInput<NumberType>:InputBase where NumberType : INumbe
{ {
await StepUp(); await StepUp();
} }
} else
{
return;
} }
} }
private string _value;
[Parameter] [Parameter]
public NumberType Value public NumberType? Value
{ {
get; get
set; {
if (string.IsNullOrEmpty(_value)) return default(NumberType);
return (NumberType)Convert.ChangeType(_value, typeof(NumberType));
}
set
{
_value = value.ToString();
}
} }
[Parameter] [Parameter]
public int DecimalPlaces { get; set; } =0; public int DecimalPlaces { get; set; } =0;
[Parameter] [Parameter]
public EventCallback<NumberType> ValueChanged { get; set; } public EventCallback<NumberType> ValueChanged { get; set; }
public async Task ChangeValueAsync(ChangeEventArgs args) public async Task GetValueAsync(ChangeEventArgs args)
{ {
if (args.Value is not null) if (args.Value is not null)
{ {
NumberType value = (NumberType)Convert.ChangeType(args.Value, typeof(NumberType)); string newVal = args.Value.ToString();
if (value.ToString().Length <= 0) if (!newVal.Equals("0"))
{ {
if (newVal.ToString().Contains("-"))
newVal = "-" + newVal.ToString().Replace("-", "");
if (newVal.ToString().ToLower().Contains("e"))
newVal = "e" + newVal.ToString().Replace("e", "");
}
if (string.IsNullOrEmpty(newVal))
{
await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(AdjustDecimalPlaces((NumberType)Convert.ChangeType(null, typeof(NumberType))), typeof(NumberType)));
}
else
{
if (!newVal.Equals(_value))
await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(AdjustDecimalPlaces((NumberType)Convert.ChangeType(newVal, typeof(NumberType))), typeof(NumberType)));
}
}
}
value = (NumberType)Convert.ChangeType(0, typeof(NumberType)); [Parameter] public EventCallback<KeyboardEventArgs> OnKeyDown { get; set; }
private bool CheckKey(string key)
{
bool result;
if (Helper.IsNumeric(key)) return true;
switch (key.ToLower())
{
case "backspace":
case "delete":
case "arrowleft":
case "arrowright":
case "-":
//case "e":
{
result = true;
break;
}
default:
{
result = false;
break;
} }
await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(AdjustDecimalPlaces(value), typeof(NumberType)));
} }
if ((key.Equals("-") || key.Equals("-")) && _value.Contains(key)) result = false;
return result;
} }
private NumberType AdjustDecimalPlaces(NumberType value) private bool _preventDefaultAction = true;
public async Task ChangeValue(KeyboardEventArgs args)
{ {
NumberType result = value; _preventDefaultAction= true;
if (Helper.NumberHasDecimalPlaces(value)) if (args is not null)
{ {
if (DecimalPlaces > 0) var key = args.Key.ToString().ToLower();
if (CheckKey(key))
{ {
decimal rounded = (decimal)Convert.ChangeType(value, typeof(decimal)); _preventDefaultAction = false;
rounded = Math.Round(rounded, DecimalPlaces);
result = (NumberType)Convert.ChangeType(rounded, typeof(NumberType)); await OnKeyDown.InvokeAsync(args);
} }
} else
{
args.Key = null;
}
}
private NumberType AdjustDecimalPlaces(NumberType value)
{
var result = value;
if (DecimalPlaces > 0)
{
double converted = Math.Round((double)Convert.ChangeType(result, typeof(double)), DecimalPlaces);
return (NumberType)Convert.ChangeType(converted, typeof(NumberType));
} }
return result; return result;
} }
private async Task Clear() private async Task Clear()
{ {
_value = string.Empty;
await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(0, typeof(NumberType))); await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(0, typeof(NumberType)));
} }
#region Lifecycle protected override async Task OnAfterRenderAsync(bool firstRender)
protected override async Task OnInitializedAsync()
{ {
if (DecimalPlaces > 0) if (firstRender)
{ {
Value = AdjustDecimalPlaces(Value); if (!DecimalPlaces.Equals(Helper.GetDecimalPlaces(Value)))
await ValueChanged.InvokeAsync(Value); {
Value = AdjustDecimalPlaces(Value);
StateHasChanged();
}
} }
} }
#region Lifecycle
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
if (typeof(NumberType).Name.ToLower().Contains("int")) if (typeof(NumberType).Name.ToLower().Contains("int"))

@ -1,5 +1,7 @@
using Connected.Utilities; using Connected.Utilities;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using static Connected.Colors;
using static System.Net.Mime.MediaTypeNames;
namespace Connected.Models; namespace Connected.Models;
public class InputBase : ComponentBase public class InputBase : ComponentBase
@ -71,6 +73,22 @@ public class InputBase : ComponentBase
} }
} }
/// <summary>
/// Fired when the text value changes.
/// </summary>
[Parameter] public EventCallback<string> TextChanged { get; set; }
public string Text { get; set; }
protected virtual async Task SetTextAsync(string text)
{
if (Text != text)
{
Text = text;
await TextChanged.InvokeAsync(text);
}
}
private string _helperText = string.Empty; private string _helperText = string.Empty;
[Parameter] [Parameter]
public string HelperText public string HelperText

@ -135,11 +135,11 @@ public static class Helper
} }
} }
public static bool IsVariableNumeric(string input) public static bool IsNumeric(string input)
{ {
try try
{ {
var number = Decimal.Parse(input); var number = Double.Parse(input);
return true; return true;
} }
catch catch

@ -10,6 +10,7 @@ namespace Connected.Utilities;
public struct StyleBuilder public struct StyleBuilder
{ {
private string stringBuffer; private string stringBuffer;
private string style;
/// <summary> /// <summary>
/// Creates a StyleBuilder used to define conditional in-line style used in a component. Call Build() to return the completed style as a string. /// Creates a StyleBuilder used to define conditional in-line style used in a component. Call Build() to return the completed style as a string.
@ -35,6 +36,7 @@ public struct StyleBuilder
/// <param name="prop"></param> /// <param name="prop"></param>
/// <param name="value"></param> /// <param name="value"></param>
public StyleBuilder(string prop, string value) => stringBuffer = $"{prop}:{value};"; public StyleBuilder(string prop, string value) => stringBuffer = $"{prop}:{value};";
public StyleBuilder(string style) : this() => this.style = style;
/// <summary> /// <summary>
/// Adds a conditional in-line style to the builder with space separator and closing semicolon. /// Adds a conditional in-line style to the builder with space separator and closing semicolon.

Loading…
Cancel
Save