14

In an asp.net-mvc project using C#.

I use a function to format larger numbers with commas such as 1,000,000, thanks to this post:

function numberWithCommas(str) {
    return str.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

The issue is, I have the inputs locked down to accept only numbers with a min value of zero.

<input type="number" min="0" class="myclass" value="@somevalue" />

This poses a problem using the JS, as it needs only number input. Which brings me to a question like this How to make HTML input tag only accept numerical values?, which also offers a JS solution.

I'm wondering if anyone has developed an elegant way to format numeric input display, while validating numeric input, is there are any other options available here? It doesn't have to purely be a JS solution.

Community
  • 1
  • 1
  • 1
    A different approach, but you might be interested in [this plugin](https://github.com/stephenmuecke/mvc-numericinput) - using `@Html.NumericInputFor(m => m.SomeNumber)` generates a 'transparent' texbox with a 'formatted' underlay. When you tab-in the textbox becomes opaque and accepts only digits and the decimal separator. When you tab-out, you see the formatted number. –  Jun 05 '16 at 10:48
  • Have you written a custom `ModelBinder` for this (if not, it will not bind to your model when you submit because of the `,` characters) –  Jun 07 '16 at 12:45
  • 1
    What C# and asp.net-mvc tags doing here? Seems not related to the question (at least C# for sure). – Evk Jun 07 '16 at 17:30
  • Validating and reformatting input data as the user types it is so fraught with weird edge cases and user annoyances that it's almost never worth the effort. – Jim Mischel Jun 07 '16 at 18:24
  • 1
    @Yvette, Wont add an answer (too involved) but I have created [this DotNetFiddle](https://dotnetfiddle.net/nX4AEN) to show how it works (the `
    ....
    ` elements are what would be created by the `@Html.NumericInputFor(m => m.Price)` method for a en-US culture)
    –  Jun 08 '16 at 00:32
  • 1
    @Yvette, It was just there to allow you to tab back and forth between the controls to see how it worked :). A full answer would also need to include the code in the `HtmlHelper` extension method which would make it too long, and an answer with just a link to the source code would be nuked :) But fell free to mention it in your answer if you want to. I'll get around to writing the README file in the GitHub this weekend I hope :) –  Jun 09 '16 at 02:04

3 Answers3

7

You can't use the numeric input, because, well, JavaScript doesn't consider formatted number to be a number.

The option is to use the non-numeric input but filter out any "problematic" chars.

In the following example, I'm also handling the dot separator in case you need to accept fractions.

As the text box is being edited, it also has to preserve the cursor position. I've achieved it there with the help of Updating an input's value without losing cursor position.

function format(inp){
  var start = inp.selectionStart,  // get the selection start
      end   = inp.selectionEnd;    // and end, as per the linked post
  var s1=inp.value.split(",").length-1; //count the commas before edit
  inp.value=numberWithCommas(inp.value.replace(/,|[^\d.]/g,''));
  var s2=inp.value.split(",").length-s1-1; //count the commas after edit so as to know where to place the cursor, as the position changes, if there are new commas or some commas have been removed
  inp.setSelectionRange(start+s2, end+s2); // set the selection start and end, as per the linked post
}
function numberWithCommas(str) {
  var a=str.split('.');
  var p=/\B(?=(\d{3})+(?!\d))/g;
  if(a.length>1)
    return a[0].toString().replace(p, ",")+"."+a[1];
  else 
    return str.toString().replace(p, ",");
}
<input onkeyup="format(this)">
Community
  • 1
  • 1
nicael
  • 18,550
  • 13
  • 57
  • 90
5

I have the answer of your first question.

You can disable all keys rather than only numbers keys.

function isNumberKey(evt)  {
    var charCode = (evt.which) ? evt.which : event.keyCode;

    if (charCode != 43 && charCode > 31
      && (charCode < 48 || charCode > 57))
        return false;
    return true;

}

I also created working demo on jsfiddle

Deep Shah
  • 310
  • 1
  • 6
  • 1
    This does not allow the decimal separator, or the negative sign :) –  Jun 07 '16 at 12:46
  • ya. but its not my need. you can edit in code (in charCode) – Deep Shah Jun 07 '16 at 13:14
  • Edit this code in if condition (second line of if condition)@StephenMuecke : " && (charCode < 47 || charCode > 57)) " . Now you can put separator also. ☺ – Deep Shah Jun 07 '16 at 13:23
2

The program flow:
Getting the input via an on change event and calling the other functions, showing passing the data through a Ajax POST.

$('.Amount').on("change", function (e) {
    var myInput = $(e.target);
    var input = this.value;
    // Remove any non digits (including commas) to pass value to controller.
    var Amount = validateInput(input);
    // Format the string to have commas every three digits 1,000,000 for display.
    var val = numberWithCommas(Amount);
    $(myInput).val(val);

    $.ajax({
        type: 'POST',
        dataType: "json",
        url: somesUrl + '/' + somethingelse,
        data: JSON.parse('{"Amount": "' + Amount + '"}'), // Amount is a nice format here and will not throw an error.
        // TODO etc
    });
});

Remove any non numbers and give a value of zero if no numbers are inputted.

var validateInput = function (input) {
    input = input.toString().replace(/[^0-9]/g, "");
    /* Remove leading zeros. */
    input = input.replace(/^0+/, '');
    if (input == "")
        input = 0;
    return input;
}

Format the input with commas 1,000,000,000.

function numberWithCommas(str) {
    return str.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

So even if the user types input with commas e.g. 1,734,567 it will work and if they misplace where they put a commas e.g. 17,35,555 it will still validate.

See working fiddle.

I actually worked out a nice solution while trying to meet project deadlines and in part this was solved by this answer by nicael.

This solution does not check the input as it is being typed, but after it is finished, I chose the change event, as opposed to the input event, as it calls the function once and (similar to a submit event) than validates the input in one call. Removing any commas and non digits; solving the issue of formatting with commas, by removing them for the ajax call, then reformatting it with commas for the display. There is a check to remove leading zeros.

If all the input is garbage I replace this value with zero to prevent an error passing to the controller with null data (just a design choice, could display a toast message instead).

Community
  • 1
  • 1