From 1fd00285573423bb805040387c3f7372fcc2d999 Mon Sep 17 00:00:00 2001 From: stm Date: Tue, 14 Feb 2023 14:30:15 +0100 Subject: [PATCH 1/6] Number Input - mousewheeel fix, prevent of enetering flase characters --- .../Components/NumberInput.razor | 20 ++- .../Components/NumberInput.razor.cs | 165 ++++++++++++++---- src/Connected.Components/Models/InputBase.cs | 18 ++ src/Connected.Components/Utilities/Helper.cs | 4 +- .../Utilities/StyleBuilder.cs | 2 + 5 files changed, 163 insertions(+), 46 deletions(-) diff --git a/src/Connected.Components/Components/NumberInput.razor b/src/Connected.Components/Components/NumberInput.razor index c451fdf..70f581a 100644 --- a/src/Connected.Components/Components/NumberInput.razor +++ b/src/Connected.Components/Components/NumberInput.razor @@ -5,18 +5,18 @@ @typeparam NumberType
- - - + @onkeydown=@(args => ChangeValue(args)) + @onkeydown:preventDefault="@_preventDefaultAction" + @oninput=@GetValueAsync + @onmousewheel=@OnMouseWheel + @onwheel="OnMouseWheel" + @bind-value="@_value" + @attributes="@InputAttributes" /> @@ -34,6 +34,10 @@ } + + + + @if (Clearable && Value.ToString().Length > 0) { diff --git a/src/Connected.Components/Components/NumberInput.razor.cs b/src/Connected.Components/Components/NumberInput.razor.cs index 00c1d8b..3615c27 100644 --- a/src/Connected.Components/Components/NumberInput.razor.cs +++ b/src/Connected.Components/Components/NumberInput.razor.cs @@ -3,11 +3,11 @@ using Connected.Utilities; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using System.Numerics; -using static Connected.Colors; namespace Connected.Components; public partial class NumberInput:InputBase where NumberType : INumber { + private double _step =1; [Parameter] public double Step { @@ -22,30 +22,56 @@ public partial class NumberInput:InputBase where NumberType : INumbe } [Parameter] - public bool DisableMouseWheel { get; set; } = false; + public bool DisableMouseWheel + { + get; + set; + } = false; private async Task StepUp() { - double num = (double)Convert.ChangeType(Value, typeof(double)); - num += _step; - Value = AdjustDecimalPlaces((NumberType)Convert.ChangeType(num, typeof(NumberType))); + try + { + 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); } private async Task StepDown() { - double num = (double)Convert.ChangeType(Value, typeof(double)); - num -= _step; - Value = AdjustDecimalPlaces((NumberType)Convert.ChangeType(num, typeof(NumberType))); + try + { + 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); } - 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; - if (obj.DeltaY < 0) + if (args.DeltaY >= 0) { await StepDown(); } @@ -53,69 +79,136 @@ public partial class NumberInput:InputBase where NumberType : INumbe { await StepUp(); } + } else + { + return; } } + private string _value; [Parameter] - public NumberType Value + public NumberType? Value { - get; - set; + get + { + if (string.IsNullOrEmpty(_value)) return default(NumberType); + return (NumberType)Convert.ChangeType(_value, typeof(NumberType)); + } + set + { + _value = value.ToString(); + } } [Parameter] public int DecimalPlaces { get; set; } =0; - [Parameter] - public EventCallback ValueChanged { get; set; } + public EventCallback ValueChanged { get; set; } - public async Task ChangeValueAsync(ChangeEventArgs args) + public async Task GetValueAsync(ChangeEventArgs args) { if (args.Value is not null) { - NumberType value = (NumberType)Convert.ChangeType(args.Value, typeof(NumberType)); - if (value.ToString().Length <= 0) - { + string newVal = args.Value.ToString(); + 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 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; - if (Helper.NumberHasDecimalPlaces(value)) + _preventDefaultAction= true; + 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)); - rounded = Math.Round(rounded, DecimalPlaces); - result = (NumberType)Convert.ChangeType(rounded, typeof(NumberType)); + _preventDefaultAction = false; + + 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; } private async Task Clear() { + _value = string.Empty; await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(0, typeof(NumberType))); } - #region Lifecycle - - protected override async Task OnInitializedAsync() + protected override async Task OnAfterRenderAsync(bool firstRender) { - if (DecimalPlaces > 0) + if (firstRender) { - Value = AdjustDecimalPlaces(Value); - await ValueChanged.InvokeAsync(Value); + if (!DecimalPlaces.Equals(Helper.GetDecimalPlaces(Value))) + { + Value = AdjustDecimalPlaces(Value); + StateHasChanged(); + } } } + #region Lifecycle protected override async Task OnParametersSetAsync() { if (typeof(NumberType).Name.ToLower().Contains("int")) diff --git a/src/Connected.Components/Models/InputBase.cs b/src/Connected.Components/Models/InputBase.cs index 3bcd5fc..a95722c 100644 --- a/src/Connected.Components/Models/InputBase.cs +++ b/src/Connected.Components/Models/InputBase.cs @@ -1,5 +1,7 @@ using Connected.Utilities; using Microsoft.AspNetCore.Components; +using static Connected.Colors; +using static System.Net.Mime.MediaTypeNames; namespace Connected.Models; public class InputBase : ComponentBase @@ -71,6 +73,22 @@ public class InputBase : ComponentBase } } + /// + /// Fired when the text value changes. + /// + [Parameter] public EventCallback 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; [Parameter] public string HelperText diff --git a/src/Connected.Components/Utilities/Helper.cs b/src/Connected.Components/Utilities/Helper.cs index 5737498..1b401ad 100644 --- a/src/Connected.Components/Utilities/Helper.cs +++ b/src/Connected.Components/Utilities/Helper.cs @@ -135,11 +135,11 @@ public static class Helper } } - public static bool IsVariableNumeric(string input) + public static bool IsNumeric(string input) { try { - var number = Decimal.Parse(input); + var number = Double.Parse(input); return true; } catch diff --git a/src/Connected.Components/Utilities/StyleBuilder.cs b/src/Connected.Components/Utilities/StyleBuilder.cs index 79c4b5b..620daab 100644 --- a/src/Connected.Components/Utilities/StyleBuilder.cs +++ b/src/Connected.Components/Utilities/StyleBuilder.cs @@ -10,6 +10,7 @@ namespace Connected.Utilities; public struct StyleBuilder { private string stringBuffer; + private string style; /// /// 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 /// /// public StyleBuilder(string prop, string value) => stringBuffer = $"{prop}:{value};"; + public StyleBuilder(string style) : this() => this.style = style; /// /// Adds a conditional in-line style to the builder with space separator and closing semicolon. -- 2.36.3 From e416c42952338c5dee14935f3671cbfe9b5ca910 Mon Sep 17 00:00:00 2001 From: stm Date: Wed, 15 Feb 2023 08:12:42 +0100 Subject: [PATCH 2/6] NumberInput - added onchange method to run Math.Round on the Value when leaving field, adjusting the decimal places provided with DecimalPlaces parameter --- .../Components/NumberInput.razor | 3 ++- .../Components/NumberInput.razor.cs | 13 +++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Connected.Components/Components/NumberInput.razor b/src/Connected.Components/Components/NumberInput.razor index 70f581a..aebe254 100644 --- a/src/Connected.Components/Components/NumberInput.razor +++ b/src/Connected.Components/Components/NumberInput.razor @@ -10,12 +10,13 @@ step="@_step" disabled="@Disabled" readonly="@Readonly" + value="@_value" @onkeydown=@(args => ChangeValue(args)) @onkeydown:preventDefault="@_preventDefaultAction" @oninput=@GetValueAsync @onmousewheel=@OnMouseWheel + @onchange="@Change" @onwheel="OnMouseWheel" - @bind-value="@_value" @attributes="@InputAttributes" /> diff --git a/src/Connected.Components/Components/NumberInput.razor.cs b/src/Connected.Components/Components/NumberInput.razor.cs index 3615c27..01a81c8 100644 --- a/src/Connected.Components/Components/NumberInput.razor.cs +++ b/src/Connected.Components/Components/NumberInput.razor.cs @@ -121,16 +121,25 @@ public partial class NumberInput:InputBase where NumberType : INumbe } if (string.IsNullOrEmpty(newVal)) { - await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType(AdjustDecimalPlaces((NumberType)Convert.ChangeType(null, typeof(NumberType))), typeof(NumberType))); + await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType((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))); + await ValueChanged.InvokeAsync((NumberType)Convert.ChangeType((NumberType)Convert.ChangeType(newVal, typeof(NumberType)), typeof(NumberType))); } } } + public async Task Change(ChangeEventArgs args) + { + if (args.Value is not null) + { + Value = AdjustDecimalPlaces((NumberType)Convert.ChangeType(args.Value, typeof(NumberType))); + } + ValueChanged.InvokeAsync(Value); + } + [Parameter] public EventCallback OnKeyDown { get; set; } private bool CheckKey(string key) -- 2.36.3 From e0c0e3dd684864bb534db8f39e0728a139020c7d Mon Sep 17 00:00:00 2001 From: stm Date: Wed, 15 Feb 2023 08:14:30 +0100 Subject: [PATCH 3/6] Added AspNetCore.Components reference --- src/Connected.Components/Connected.Components.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Connected.Components/Connected.Components.csproj b/src/Connected.Components/Connected.Components.csproj index 10b55ec..26aa909 100644 --- a/src/Connected.Components/Connected.Components.csproj +++ b/src/Connected.Components/Connected.Components.csproj @@ -27,6 +27,7 @@ + -- 2.36.3 From 1eb7202561f632b218f6119e2ed32c61d2d19dc5 Mon Sep 17 00:00:00 2001 From: stm Date: Wed, 15 Feb 2023 09:38:24 +0100 Subject: [PATCH 4/6] Removed unnecessary SatateHasChanged() on Textinput --- .../Pages/Index.razor | 105 +++--------------- .../Components/TextInput.razor.cs | 2 - src/Connected.Components/Models/SelectItem.cs | 9 -- 3 files changed, 16 insertions(+), 100 deletions(-) delete mode 100644 src/Connected.Components/Models/SelectItem.cs diff --git a/src/Connected.Components.Showcase.Runner/Pages/Index.razor b/src/Connected.Components.Showcase.Runner/Pages/Index.razor index 748b937..6f94a83 100644 --- a/src/Connected.Components.Showcase.Runner/Pages/Index.razor +++ b/src/Connected.Components.Showcase.Runner/Pages/Index.razor @@ -3,112 +3,39 @@

Component Sandbox

-

ValueDouble: @inputValueDouble.ToString()

-

ValueInt: @inputValueInt.ToString()

-

ValueText: @inputValueText

-

SimpleSelectValue: @SelectedItemValue

- - - - - - - - - - - +

SelectedValue: @SelectedValue.ToString()

- + Items="@items" + Label="Simple select" + @bind-Value=@SelectedValue +/> @code { + int SelectedValue; - List> SelectFieldItems = new(); - string SelectedItemValue = ""; - - int counter { get; set; } = 0; + List items; - private string _inputText = string.Empty; - string inputValueText + private void FillItemsList() { - get - { - return _inputText; - } - set - { - if (value.Length > 0) errorText = "Error!!!"; - else errorText = ""; - _inputText = value; - StateHasChanged(); - } - } - double inputValueDouble = 12.756; - int inputValueInt = 12; + if (items is null) items = new(); - DateTime inputValueDate = DateTime.Now.AddDays(-10); + Random random = new Random(DateTime.Now.Millisecond); - public void CounterIncrement() - { - counter++; + for (int i = 0; i < 10; i++) + { + int item = random.Next(); + items.Add(item); + } StateHasChanged(); } - string errorText = "Error!!"; - protected override async Task OnInitializedAsync() { - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 1", Value = "select item value 1", Enabled = true }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 2", Value = "select item value 2", Enabled = true }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 3", Value = "select item value 3", Enabled = true }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 4", Value = "select item value 4", Enabled = true }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 5", Value = "select item value 5", Enabled = false }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 6", Value = "select item value 6", Enabled = true }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 7", Value = "select item value 7", Enabled = true }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 8", Value = "select item value 8", Enabled = false }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 9", Value = "select item value 9", Enabled = true }); - SelectFieldItems.Add(new SelectItem() { DisplayedText = "Item 10", Value = "select item value 10", Enabled = true }); - SelectedItemValue = SelectFieldItems[0].Value; + FillItemsList(); } } \ No newline at end of file diff --git a/src/Connected.Components/Components/TextInput.razor.cs b/src/Connected.Components/Components/TextInput.razor.cs index 7dd294f..e7e5354 100644 --- a/src/Connected.Components/Components/TextInput.razor.cs +++ b/src/Connected.Components/Components/TextInput.razor.cs @@ -48,13 +48,11 @@ public partial class TextInput: InputBase private async Task ChangeValueAsync(ChangeEventArgs args) { await ValueChanged.InvokeAsync(args.Value.ToString()); - StateHasChanged(); } private async Task Clear() { await ValueChanged.InvokeAsync(string.Empty); - StateHasChanged(); } diff --git a/src/Connected.Components/Models/SelectItem.cs b/src/Connected.Components/Models/SelectItem.cs deleted file mode 100644 index bf47c79..0000000 --- a/src/Connected.Components/Models/SelectItem.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Connected.Models -{ - public class SelectItem - { - public string DisplayedText { get; set; } - public ValueType Value { get; set; } - public bool Enabled { get; set; } - } -} \ No newline at end of file -- 2.36.3 From ca4aab40022b3bc1d4ee5c36f3a7a25ff9502791 Mon Sep 17 00:00:00 2001 From: markosteger Date: Wed, 15 Feb 2023 10:01:16 +0100 Subject: [PATCH 5/6] Simple select - working version with searchbox outside --- .../Components/SimpleSelect.razor | 25 ++++++---- .../Components/SimpleSelect.razor.cs | 49 +++++++++++++------ 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/Connected.Components/Components/SimpleSelect.razor b/src/Connected.Components/Components/SimpleSelect.razor index facc072..2d895a7 100644 --- a/src/Connected.Components/Components/SimpleSelect.razor +++ b/src/Connected.Components/Components/SimpleSelect.razor @@ -4,15 +4,22 @@ @inherits InputBase; -
- -
\ No newline at end of file + +
+} \ No newline at end of file diff --git a/src/Connected.Components/Components/SimpleSelect.razor.cs b/src/Connected.Components/Components/SimpleSelect.razor.cs index 4bdfdc2..d94a841 100644 --- a/src/Connected.Components/Components/SimpleSelect.razor.cs +++ b/src/Connected.Components/Components/SimpleSelect.razor.cs @@ -1,5 +1,6 @@ using Connected.Models; using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; using System; namespace Connected.Components; @@ -9,30 +10,51 @@ public partial class SimpleSelect : InputBase public ValueType Value { get; set; } [Parameter] - public IEnumerable> Items { get; set; } + public IEnumerable Items { get; set; } - public IEnumerable> OriginalItems { get; set; } + public IEnumerable OriginalItems { get; set; } [Parameter] public bool EnableSearch { get; set; } = true; - public string SearchText { get; set; } - public void FilterItems() + private string _searchText { get; set; } = string.Empty; + public string SearchText { - Items= Items.Where(item => item.Value.ToString().ToLower().Contains(SearchText.ToLower()) || item.DisplayedText.ToString().ToLower().Contains(SearchText.ToLower())); + get + { + return _searchText; + } + set + { + _searchText = value; + FilterItems(); + } + } + + private async Task FilterItems() + { + if (string.IsNullOrEmpty(_searchText)) + { + Items = OriginalItems; + } + else + { + Items = Items.Where(item => item.ToString().ToLower().Contains(_searchText.ToLower())); + } + StateHasChanged(); } - [Parameter] - public EventCallback ValueChanged { get; set; } + [Parameter] + public EventCallback ValueChanged { get; set; } - private async Task ChangeValueAsync(ChangeEventArgs args) - { - await ValueChanged.InvokeAsync((ValueType)Convert.ChangeType(args.Value, typeof(ValueType))); - } + private async Task ChangeValueAsync(ChangeEventArgs args) + { + await ValueChanged.InvokeAsync((ValueType)Convert.ChangeType(args.Value, typeof(ValueType))); + } protected override async Task OnParametersSetAsync() - { + { if (base.InputAttributes is null) base.InputAttributes = new(); if (base.Required) { @@ -40,6 +62,5 @@ public partial class SimpleSelect : InputBase } OriginalItems = Items; await base.OnInitializedAsync(); - } - + } } \ No newline at end of file -- 2.36.3 From 45380821ad5d42972d7209ea349a1074e2f6162c Mon Sep 17 00:00:00 2001 From: markosteger Date: Wed, 15 Feb 2023 13:04:44 +0100 Subject: [PATCH 6/6] SimpleSelect - working example, waiting for css fix for not closing the select box upon clicking inside it --- .../Components/SimpleSelect.razor | 59 +++++++++++++++---- .../Components/SimpleSelect.razor.cs | 26 +++++++- 2 files changed, 70 insertions(+), 15 deletions(-) diff --git a/src/Connected.Components/Components/SimpleSelect.razor b/src/Connected.Components/Components/SimpleSelect.razor index 2d895a7..ec9c163 100644 --- a/src/Connected.Components/Components/SimpleSelect.razor +++ b/src/Connected.Components/Components/SimpleSelect.razor @@ -6,20 +6,53 @@ @if (Items is not null) { -
- @if (EnableSearch) - { - - } - + + @if (IsLabel) { - @if (item is not null) + + } + + + + + + @if (Clearable) { - + + + } - } - -
+ + + + @if (IsError) + { + + + + } + + + } \ No newline at end of file diff --git a/src/Connected.Components/Components/SimpleSelect.razor.cs b/src/Connected.Components/Components/SimpleSelect.razor.cs index d94a841..2baadb7 100644 --- a/src/Connected.Components/Components/SimpleSelect.razor.cs +++ b/src/Connected.Components/Components/SimpleSelect.razor.cs @@ -1,7 +1,5 @@ using Connected.Models; using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; -using System; namespace Connected.Components; public partial class SimpleSelect : InputBase @@ -31,6 +29,29 @@ public partial class SimpleSelect : InputBase } } + private string DropDownClass { get; set; } = "drop-down"; + + bool DropDownClicked = false; + + public void DropDownClassToggle() + { + DropDownClicked = !DropDownClicked; + if (DropDownClicked) + { + DropDownClass = ""; + } else + { + DropDownClass = "drop-down"; + } + StateHasChanged(); + } + + private async Task SetSelectedItem(ValueType item) + { + //DropDownClassToggle(); + await ValueChanged.InvokeAsync(item); + } + private async Task FilterItems() { if (string.IsNullOrEmpty(_searchText)) @@ -61,6 +82,7 @@ public partial class SimpleSelect : InputBase if (base.InputAttributes.ContainsKey("required")) base.InputAttributes.Add("required", true); } OriginalItems = Items; + if (_searchText.Length>0) await FilterItems(); await base.OnInitializedAsync(); } } \ No newline at end of file -- 2.36.3