7

I am writing a directive that will validate the Swedish social security number (personnummer). To be used on an input element like this:

<input type="text" ng-model="pnr" pnrvalidator />

The Swedish social security number is on the format yyyymmdd-nnnn e.g 19121212-1212

My directive works as long as I use type="text". But since I would like that the number keyboard is used on mobile browsers, then I changed to type="number":

<input type="number" ng-model="pnr" pnrvalidator />

Then my validator only works if I don't enter a dash (-) in my input e.g 191212121212 . If I enter 19121212-1212 then it's not a valid number. And the classes ng-invalid ng-invalid-number is added to my input element

When I wrote my directive I followed the documentation how to modifying built-in validators https://docs.angularjs.org/guide/forms But it doesn't seem to apply to type=number validation, or do I miss something? I am using angular 1.3 (and 1.4).

My directive code:

angular.module('example').directive('pnrvalidator', function(){
return {
    require: 'ngModel',
    link: function(scope, elm, attrs, ctrl) {


    var validatePnr = function(inputString){
        /*
        * My validation logic here. Removed for this example
        */

    };


    ctrl.$validators.number = function(modelValue, viewValue) {
        if (ctrl.$isEmpty(modelValue)) {
          // consider empty models to be valid
          return true;
        }
        if (validatePnr(viewValue)) {
          // it is valid
          return true;
        }
        // it is invalid
        return false;
    };
    }
};
});

A plunker with my example http://plnkr.co/edit/OFYG06YEFwKg8zrLYVN1?p=preview

Lars J
  • 111
  • 1
  • 4

3 Answers3

0

you can tell html to not to validate html form by novalidate attribute in tag. As you are validating in angularjs you don't need it to be validated again by HTML.

http://www.w3schools.com/tags/att_form_novalidate.asp

Zeel Shah
  • 462
  • 6
  • 15
0

HTML will not allow anything but a number or decimal (when using step="any" to be considerate valid this will force angular to consider it invalid... however you can create your own validation method in the controller:

$scope.validated = function(){

      if (null !== $scope.pnr) ){
        $scope.pnr = $scope.pnr.split("-").join();
        if(typeof parseInt($scope.pnr, 10) = 'integer') return true;
            else return false;
      } else {
        return false;
      }
    };

this is just a random validation not necessarily what you want...

Then have it have an ng-class of "error" which is on if validated ===false

something like :

<form name="myForm" ng-submit="validated && submittedSSN">
ng-class="{strike: deleted, bold: important, 'has-error': error}"
<input type="number" ng-class=" {error: !validated}" ng-model="pnr" pnrvalidator />
</form>

The CSS will also have to have something for error.

.error {
   background: red;
    border:red;
    color: lime;
}

--Note this a joke that will be crazy..

https://docs.angularjs.org/api/ng/directive/ngClass

Also See: iPhone UIWebview: How to force a numeric keyboard? Is it possible? How to add custom validation to an AngularJS form?

According to this you can do type="tel" which will work on Safari only.

Community
  • 1
  • 1
Zargold
  • 1,892
  • 18
  • 24
  • step="any" does not solve the problem. I could use type="text" but then I don't get the number keyboard on mobile devices. – Lars J Jul 18 '15 at 19:47
  • I updated it with a custom strategy using angular: you create a validation method in that controller. you don't let ng-invalid have a red class you let your own method determine if something has an ng-class="{ – Zargold Jul 18 '15 at 19:53
0

I have done some more research on my problem with <input type="number"/> and custom validation for numbers containing dashes e.g 1234-1234. And it seems that it is not possible to solve this right now. (I would like to use type="number" to get a numeric keybord on mobile browsers)

It is possible to disable angulars number validation by removing all parsers in my directive link funktion

ctrl.$parsers = [];

Then angular says it is a valid number and adding the class ng-valid-number. But that doesn't help, because the browser (except IE11) will return an empty string when entering a number containing a dash in the middle e.g 1234-1234.

According to How to get the raw value an <input type="number"> field? and https://html.spec.whatwg.org/multipage/forms.html#states-of-the-type-attribute this is correct behaviour for the browser according to the HTML spec. It can be tested with this code:

<!DOCTYPE html>
<html>
  <head>
    <script data-require="jquery@2.1.4" data-semver="2.1.4" src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
  </head>
  <body>
    <h1>Input test</h1>
    <input type="number" id="myInput"/>
    Value=<span id="myValue"></span>
    <script>
      $('#myInput').keyup(function(){
        var value = $(this).val();
        $('#myValue').text(value);
      });
    </script>
  </body>
</html>

You could use type="tel" but on iOS you get a numeric keyboard without the dash. So that won't work for me either. A great blog post that describes the different browser support for different input types: http://www.smashingmagazine.com/2015/05/form-inputs-browser-support-issue/

In the HTML 5.1 spec there is proposed another attribute 'inputmode' that can have the value 'numeric' inputmode="numeric". Inputmode is supposed to tell the browser what kind of input mechanism would be most helpful for users entering content into the form control. https://html.spec.whatwg.org/#input-modalities:-the-inputmode-attribute. But there is no browser support yet. http://www.wufoo.com/html5/attributes/23-inputmode.html

So it seems that for now I have to use <input type="text"/>

Community
  • 1
  • 1
Lars J
  • 111
  • 1
  • 4