Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

input type="number" does not allow numbers with leading decimals on some browsers #5680

Open

Description

@joeenzminger

Fiddle: http://jsfiddle.net/NEhG9/3/

The fiddle uses 1.2.1, however, I have reproduced it using 1.2.6

It affects IE9 and Firefox
It does not affect Chrome or Safari

I haven't tested IE8- or IE10+

The desired behavior is to allow the leading decimal to be entered, but do not update the model or set the input element's validation to valid until a valid number is entered.

Users can enter numbers with leading decimals by entering the number first, then scrolling back and entering the decimal.

Activity

  1. added a commit that references this issue on Jan 8, 2014
    58ac268
  2. ghost assigned on Jan 9, 2014
  3. rnicholus commented on Apr 9, 2015

    @rnicholus

    Instead of modifying the angular source, I'm using a custom validator that I attach to number fields to work around this issue. This appears to consistently mark the field as invalid until a valid number is entered, cross-browser. This also seems to address the issue in IE9 where leading decimals are removed.

    module.directive('tolerantNumber', function() {
        return {
            require: 'ngModel',
            priority: 1,
            link: function(scope, element, attrs, ctrl) {
                var ngNumberParser = ctrl.$parsers.splice(0, 1)[0];
    
                ctrl.$parsers.push(function(value) {
                    if (value === '.') {
                        ctrl.$setValidity('number', false);
                        return undefined;
                    }
                    return ngNumberParser(value);
                });
            }
        };
    });

    Use:

    <input type="number" tolerant-number>

    I'm not sold on the directive name though. Oh well.

  4. rnicholus commented on Apr 10, 2015

    @rnicholus

    After closer inspection, the above code doesn't solve additional problems I'm seeing in IE10+. I just ended up contributing my own number validator directive and switched to a text input. This appears to be the only obvious way to properly validate numbers cross-browser.

  5. joeenzminger commented on Apr 10, 2015

    @joeenzminger
    Author

    Ray, can you reference the commit with your number validator? I'd like to take a look at it.

  6. rnicholus commented on Apr 10, 2015

    @rnicholus

    The commit is in a private project, but I'll post it below. I wrote a few unit tests that seem to verify it, and some brief cross-browser testing looks good:

    module.directive('numberValidator', function() {
        return {
            require: 'ngModel',
            link: function(scope, element, attrs, ctrl) {
                ctrl.$parsers.push(function(value) {
                    if (ctrl.$isEmpty(value)) {
                        ctrl.$setValidity('number', true);
                        return null;
                    }
                    // http://stackoverflow.com/a/1830844/486979
                    else if (!isNaN(parseFloat(value)) && isFinite(value)) {
                        ctrl.$setValidity('number', true);
                        return value;
                    }
                    else {
                        ctrl.$setValidity('number', false);
                    }
                });
            }
        };
    });
  7. rnicholus commented on Apr 10, 2015

    @rnicholus

    Here are my tests:

    describe('number validator', function() {
        var $scope, $compile, el;
    
        beforeEach(function() {
            module('module');
            module('test.templates');
    
            inject(function(_$rootScope_, _$translate_, _$compile_) {
                $scope = _$rootScope_.$new();
                $compile = _$compile_;
    
                $scope.test = {num: null};
                el = '<input type="text" ng-model="test.num" number-validator>';
                el = $compile(el)($scope);
                $scope.$digest();
            });
        });
    
        it('declares valid numbers to be valid', function() {
            el.val('1').trigger('input');
            expect(el.hasClass('ng-valid')).toBe(true);
    
            el.val('.1').trigger('input');
            expect(el.hasClass('ng-valid')).toBe(true);
    
            el.val('1.0').trigger('input');
            expect(el.hasClass('ng-valid')).toBe(true);
    
            el.val('-1.0').trigger('input');
            expect(el.hasClass('ng-valid')).toBe(true);
        });
    
        it('declares invalid numbers to be invalid', function() {
            el.val('-').trigger('input');
            expect(el.hasClass('ng-invalid')).toBe(true);
    
            el.val('.').trigger('input');
            expect(el.hasClass('ng-invalid')).toBe(true);
    
            el.val('abc').trigger('input');
            expect(el.hasClass('ng-invalid')).toBe(true);
        });
    });
  8. stewones commented on Sep 1, 2015

    @stewones

    +1

  9. willmendesneto commented on Apr 6, 2016

    @willmendesneto

    I had a similar problem and update the input[type="number"] example on angular docs for works with decimals precision and I'm using this approach to solve it.

    ...
    .directive('stringToNumber', function() {
      return {
        require: 'ngModel',
        link: function(scope, element, attrs, ngModel) {
          var decimalPrecision = attrs.decimalPrecision || 0;
          ngModel.$parsers.push(function(value) {
            return value;
          });
    
          function updateElementValue() {
            var viewValue = parseFloat(ngModel.$viewValue || 0);
            element.val(decimalPrecision !== null ? viewValue.toFixed(decimalPrecision) : viewValue);
          }
    
          ngModel.$formatters.push(function(value) {
            return parseFloat(value, 10);
          });
    
          ngModel.$viewChangeListeners.push(updateElementValue);
    
          ngModel.$render = function() {
            updateElementValue();
          }
        }
      };
    });
    <input type="number" 
               string-to-number 
               decimal-precision="2" 
               ng-model="model.value" 
               step="0.10" />

    Here is the plunker with this snippet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions