0

NOTE: I know this is similar to other questions, but for semantic and other reasons (e.g. ease of input on iOS) I specifically want the HTML input to be type="number". This is where the problem comes in....

I'm trying to set up an HTML form so that number fields show thousands commas -- e.g. "10,000,000" instead of "10000000". I want to set it so that the field displays the commas, but when it gets focus for actual editing the commas go away.

I can manually add commas to the value without any issue (I'm testing mainly in Firefox ~59); but any time I try to have JavaScript add the commas, the field is blanked out instead. Does anyone know how to make this work?

(Note, I'm using Numerals.js for formatting here... http://numeraljs.com/ )

Here is what I have:

$(document).ready(function(){
    var numberFields = $("input[type=number]");
    numberFields.each( function(){
        $(this).val( numeral( $(this).val() ).format('0') );
    });
    numberFields.focus( function(){
        $(this).val( numeral( $(this).val() ).format('0') );
    });
    numberFields.blur( function(){
        $(this).val( numeral( $(this).val() ).format('0,0') );
    });
});

Example HTML input:

<input name="myField" value="0" type="number">

(Incidentally -- and conveniently, I've confirmed that submitting a number with commas to the HTML form processing script just drops the commas and puts the unformatted number into the DB. Sweet!)

13
  • 1
    If you use the HTML typed inputs, you have to accept the HTML rules for number parsing. Those do not allow for commas. Commented Apr 5, 2018 at 21:31
  • Yeah, I know. I have noted that if you put the cursor in the field and just plain type commas, it accepts those just fine. Hoping there's some way JS can do what I can do with my keyboard.... Commented Apr 5, 2018 at 21:32
  • 1
    Use type="text" pattern="[0-9,]*" to restrict it to numbers with commas. Commented Apr 5, 2018 at 21:33
  • Yes, you can type what you want in the field, but when your form is posted or you access .value from JavaScript, you get nothing. It's unsatisfying behavior, I agree. Commented Apr 5, 2018 at 21:33
  • You can also use Javascript form validation. Commented Apr 5, 2018 at 21:33

3 Answers 3

3

I'm not familiar with numeral.js, but if I were doing it, I would just save the numeric value as a data attribute, and then format with .toLocaleString, keeping in mind that you have switch between text and number types so that you can display your commas:

Seeing the issues with iOS, I believe the following will work. You can clone the element, THEN set the original to be a text input. Then, get the position of the original, and set the new element to be absolutely positioned over the original. Now, set the number input to opacity: 0, this way you won't see it, but when they click, it will click your clone. When the clone is clicked, set it to opacity: 1, and when it is blurred, set the original input to the cloned input's value, but using toLocaleString. I checked that it works in firefox, in theory it should work on iOS as well.

$(document).ready(function(){
        var $clones = [];
        var numberFields = $("input[type='number']");
        numberFields.each(function(i){
            var $clone = $(this).clone();
            $(this).attr('type', 'text');
            var destination = $(this).offset();
            var width = $(this).width();
            $clones.push($clone.css({
                position: 'absolute',
                top: destination.top,
                left: destination.left,
                opacity: '0',
                width: width
            }));
            $(this).after($clone);
            var that = this;
            $clone.on('focus', function() {
                $(this).css('opacity', '1');
            });
            $clone.on('blur', function() {
                $(this).css('opacity', '0');
                $(that).val('' + $(this).val() ? parseInt($(this).val()).toLocaleString() : '');
            });
        });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" pattern="[0-9,]*" />

Sign up to request clarification or add additional context in comments.

6 Comments

Numeral.js allows this: numeral( $(this).val() ).format('0,0'). I was avoiding toLocaleString because there is no fromLocaleString, but in your example I don't need that. Nice idea!
Bonus: I was unfamiliar with the "pattern" attribute. :-)
Aaaaand it doesn't help with iOS browsers either. Apparently mobile Safari browser decides what type of keyboard a field gets before the focus event applies. Conceptually your answer is great, but in practical terms it just doesn't quite work out. :-(
I literally LOLed when I saw your update. Just crazy that this should be so convoluted; but your code looks solid. I'll have to test tomorrow.
I suppose for desktops it would also be smart to set the tab index on the original (display) fields to -1 so those fields can’t actually be selected via keyboard
|
0

NOTE: I'm leaving this original answer in case something here is useful down the road; but please see my other answer, which is a complete solution to the original question.

I've found no way to quite do what I want. Futzing with input "type" is too inconsistent in different browsers; and doesn't work anyway on iOS (which was 90% of the point). However, I did get "pretty close" working smoothly with the following. (NOTE this uses the numeral.js library for formatting):

JavaScript:

<script>
$(document).ready(function(){
    var intFields = $("input[data-format=integer]");
    intFields.each( function(){
        $(this).attr( "pattern", "[0-9,]*" );
        $(this).val( numeral( $(this).val() ).format('0,0') );
    });
    intFields.focus( function(){
        $(this).val( numeral( $(this).val() ).format('0') );
    });
    intFields.blur( function(){
        $(this).val( numeral( $(this).val() ).format('0,0') );
    });
    $("form#myForm").on( "submit", function(){
        intFields.each( function() {
            $(this).val( numeral( $(this).val() ).format('0') );
        } );
        return true;
    } );
});
</script>

HTML:

<input type="text" data-format="integer" name="some_number" value="12345678>">

Overall, WAAAY too much work for such a common use-case. I hope browsers makers come up with a solution to this soon! There needs to be a simple, standard way to display numbers in fields.

Comments

0

My final function, based on Dave's answer. Dave's was not fully functional (though an effective proof of concept). This handles the name attribute (which is necessary for Form submit), and positions the input overlay relative to the original input, rather than the page (which prevents things going catywampus if the window is resized).

IMPORTANT: When using this, you must use <label>...</label><input>, NOT <label>...<input></label> for your number fields Fixed!:

$(document).ready(function() {
      format_integers();
    });

    /**
     * Any form inputs with type=number and data-format=integer will display contents with commas when input not in focus.
     * @param container string to be used as jQuery search. Defaults to 'body'; but can be any specific element
     */
    function format_integers(container) {
      container = (typeof container !== 'undefined') ? container : 'body';
      var $wrapper = $('<span>').css({
        position: 'relative',
        display: 'inline-block',
        padding: 0
      });
      $(container + " input[type='number'][data-format=integer]").each(function() {
        var $clone = $(this).clone();
        var $parentLabel = $(this).parent('label');
        if( $parentLabel.length !== 0 ) {
            $parentLabel.css( 'display', 'inline-flex' );
            $clone.css( 'order', 1 );
            $(this).css( 'order', 2 );
        }
        $(this).wrapAll($wrapper).css({
            position: 'absolute',
            top: 0,
            left: 0,
            opacity: 0
          })
          .attr('pattern', '[0-9]*');
        $clone.removeAttr('name class id pattern')
          .attr('type', 'text')
          .attr('tabindex', -1)
          .css('width', $(this).width)
          .val($(this).val() ? parseInt($(this).val()).toLocaleString() : '');
        $(this).before($clone);
        $(this).on('focus', function() {
          $(this).css('opacity', '1');
        });
        $(this).on('blur', function() {
          $(this).css('opacity', '0');
          $clone.val($(this).val() ? parseInt($(this).val()).toLocaleString() : '');
        });
      });
    }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
  <label>Integer Input:&nbsp; <input type="number" data-format="integer" name="test" id="num_input" value="123456789" /></label><br>
  <label for="num_input2">Integer Input: </label>
  <input type="number" data-format="integer" name="test2" id="num_input2" value="10000000" /><br>
  <label>Textarea <textarea>Something to focus other than the number fields</textarea></label>
</form>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.