5

In a Blazor application, I have an <input type="text" /> and I'm trying to do something so that non-digit characters cannot be entered into it.

This is what I've so far, and it seems to be working pretty well:

<input type="text" @bind="InputContent" @bind:event="oninput" />

@code {
    string inputContent;
    string InputContent
    {
        get => inputContent;
        set => inputContent = StripNonDigits(value);
    }

    string StripNonDigits(string str)
    {
        return new String(str.Where(c => char.IsDigit(c)).ToArray());
    }
}

Now, I'm wondering:

  • What other ways there are to achieve this very goal: "Monitoring and potentially modifying what's typed into an input by the user, in Blazor, specifically." Can this, for example, be achieved without using @bind?
  • Are there potential problems with the way I'm doing it? Or is it an optimal solution?

In JS, to do the very same thing, you would listen to the oninput event and if the entered character is not a digit, you then do an event.preventDefault(). You can't exactly do that in Blazor, as far as I know, is that right?

Arad Alvand
  • 8,607
  • 10
  • 51
  • 71
  • Why can't you use input type="number"? – Mister Magoo Jan 09 '21 at 00:27
  • 1
    @MisterMagoo That doesn't prevent the user from entering non-digits, you could still type characters like "." in an `input type="number"`, there are several other reasons as well, like the fact that the number goes up and down if you scroll in an `input type="number" which can be undesirable if the number represents something like a credit card number for instance, etc. – Arad Alvand Jan 09 '21 at 11:43
  • But it does prevent those types characters reaching your code. What is the real problem you are trying to solve? – Mister Magoo Jan 09 '21 at 11:44
  • 1
    @MisterMagoo I'm not the first person ever to want to build such an input field, see [this question](https://stackoverflow.com/questions/469357) for example. This is not a new thing, I just wanted to know how to best do this in Blazor specifically – Arad Alvand Jan 09 '21 at 11:47

2 Answers2

1

The Unreliable Solution:

Here's why @enet's proposed solution, is in fact highly unreliable, flawed, inefficient, and naive. + Why his claims that my solution is problematic are actually false.

Update: He deleted his answer.

First, reasons why his solution is inelegant:

Reason 1: Can't prevent copy-paste via shortcut keys (Ctrl/CMD + V)

No comment:

enter image description here

Reason 2: Can't prevent copy-paste via the context menu (Right-click => Paste)

No comment:

enter image description here

Reason 3: Can't prevent drag-and-drop of text

No comment:

enter image description here

Reason 4: Works only for English digits

No comment:

enter image description here

Reason 5: The middle of the text is uneditable (IMPORTANT!)

No comment:

enter image description here

Note: You could see all of these behaviors for yourself in this fiddle: https://blazorfiddle.com/s/xfik4hnq

Reason 6: Uses RegEx

RegEx is slow, inefficient, and often hard-to-read and parse. It should therefore be avoided wherever possible.

enter image description here

Reason 7: Much more complex and less elegant

Seriously, no comment, pretty obvious.

Reason 8: Requires more lines of code

Considering only the @code section, this solution, as presented by @enet, is about 23 lines of code, while mine, is about 12. (Both considering the curly braces on a line, etc.)

Note: It's also crucial to keep in mind that if this solution were to be even nearly as robust as the one I initially proposed (I'll explain that in just a bit), it would have to solve every single one of the problems that were just demonstrated, and in order to do so, it has to become much more complex than it already is, and it would require many more lines of code as well.

The Optimal Solution:

Here's why the solution that I initially proposed in my original question is the most optimal and elegant solution;

Solves ALL of the aforementioned problems, and it also does so in fewer lines of code + code that's easier-to-understand, shorter, nicer, and simpler.

Meanwhile, the only argument presented from the other side, in favor of the other solution, and against mine, was that my solution causes the disallowed characters to show up a fraction of a second, and then disappear. However, this was not observed at all in any of my tests.

Here's a GIF that demonstrates this:

Whenever I press a key on the keyboard, you can see on the console that a message like "Key pressed: a" is shown, but at the same time, you see that that character doesn't appear at all in the input:

enter image description here

Arad Alvand
  • 8,607
  • 10
  • 51
  • 71
0

Maybe the validation thing helps you? Normally it triggers on submit, but here is described how to trigger on input using a new input component that inherits from InputText: link

> @* Inherits from the original InputText component *@
@inherits InputText
@* Bind the oninput event *@
<input @attributes="AdditionalAttributes"
       class="@CssClass"
       value="@CurrentValue"
       @oninput="EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />

Then you can use a regex to not allow digits:

@using System.ComponentModel.DataAnnotations;

<EditForm Model="example">
    <DataAnnotationsValidator />
    <ValidationSummary />
    <InputTextOnInput @bind-Value="example.Name"></InputTextOnInput>
    <button type="submit">Submit</button>
</EditForm>


@code {

public class ExampleModel
{
    [Required]
    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$",
     ErrorMessage = "Characters are not allowed.")]
    public string Name { get; set; }
}

public ExampleModel example = new ExampleModel();

}

Stefan
  • 75
  • 6