1

I am trying to write custom directive for USA telephone number using angularjs and need to preserve the data type of the field as integer.Here is the jsfiddle directive and need help to complete the directive.

If user enters a valid telephone no (exactly 10 numbers ie.1234567890) then input should split into 3 chunks as 123-456-7890 when the user moves to next control.otherewise I should show error message "not a valid number".

<div ng-app="myApp" ng-controller="myCtrl">
<form name="myForm">
    <input type="text" ng-model="telephone" phoneformat  name="input1" />
     <span class="error" ng-show="myForm.input1.$error.telephone">Numbers only!</span>
    <span class="error" ng-show="myForm.input1.$error.telephone">Exact 10 Numbers only!</span>

</form>
</div>

var myApp = angular.module("myApp", []);

var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
$scope.telephone = "1234567890";
}]);

 myApp.directive("phoneformat", function () {
  return {
    restrict: "A",
    require: "ngModel",
    link: function (scope, element, attr, ngModelCtrl) {
        var phoneformat = function () {

        }

      }
    };
 });
user2580179
  • 259
  • 6
  • 15

4 Answers4

0

You might want to use http://angular-ui.github.io/ui-utils/ Mask directive.

Artemis
  • 4,821
  • 3
  • 21
  • 24
  • Thank you all. @Patrick can we avoid following line in directive ? ie.hard coded field name (telephone) .Because I want to use this directive in couple of forms and this directive is common for all the modules ngModelCtrl.$setValidity("telephone", isValid); – user2580179 Sep 23 '14 at 01:01
0

Working Fiddle: http://jsfiddle.net/HB7LU/6581/

myApp.directive("phoneFormat", function () {

return {
    restrict: "A",
    link: function (scope, element, attr) {

        element.bind('change', function() {
            if ( this.value.length === 10 ) {
               var number = this.value;
               this.value = number.substring(0,3) + '-' + number.substring(3,6) + '-' + number.substring(6,10)
            }
            else {
                document.querySelector('.helpblock').innerHTML = 'error in formatting';
            }
        });

    }
};

});

bencripps
  • 2,025
  • 3
  • 19
  • 27
0

Iv'e extended your original fiddle. here's the result: http://jsfiddle.net/10k58awt/

You can find splittedNumber array (contains 3 parts of number) on form submission

js:

var myApp = angular.module("myApp", []);

var myCtrl = myApp.controller("myCtrl", ["$scope", function ($scope) {
    $scope.telephone = "1234567890";
    $scope.submit = function () {

        var splittedNumber = [$scope.telephone.substring(0, 3), $scope.telephone.substring(3, 6), $scope.telephone.substring(6, 10)];

        // Do something with splitted number
        console.log(splittedNumber);
    };
}]);

myApp.directive("phoneformat", function () {
    return {
        restrict: "A",
        require: "ngModel",
        link: function (scope, elm, attrs, ctrl) {
            ctrl.$parsers.unshift(function (phoneInput) {
                phoneInput = phoneInput.trim();
                if (phoneInput && phoneInput.length == 10 && !isNaN(phoneInput)) {
                    ctrl.$setValidity('phoneformat', true);
                    return phoneInput;
                } else {
                    ctrl.$setValidity('phoneformat', false);
                    return undefined;

                }
            });
        }
    };
});

html:

<div ng-app="myApp" ng-controller="myCtrl">
    <form name="myForm" novalidate ng-submit="myForm.$valid && submit()">
        <input type="text" ng-model="telephone" phoneformat name="input1" /> <span class="error" ng-show="myForm.input1.$error.phoneformat">Invalid US Phone number!</span>

        <div>
            <button class="btn btn-primary" type="submit" ng-class="{'disabled': !myForm.$valid}">submit</button>
        </div>
    </form>
</div>
Jossef Harush Kadouri
  • 32,361
  • 10
  • 130
  • 129
0

It looks like you want to leverage the $error property of the form to drive validation. To do this, you will need to call $setValidity in the ngModelCtrl that you have required into your directive:

var myApp = angular.module("myApp", []);

var myCtrl = myApp.controller("myCtrl",["$scope", function($scope) {
    $scope.telephone = "1234567890";
}]);

myApp.directive("phoneformat", function () {
    return {
        restrict: "A",
        require: "ngModel",
        link: function (scope, element, attr, ngModelCtrl) {
            //Parsing is performed from angular from view to model (e.g. update input box)
            //Sounds like you just want the number without the hyphens, so take them out with replace
            var phoneParse = function (value) {
                var numbers = value && value.replace(/-/g, "");
                if (/^\d{10}$/.test(numbers)) {
                    return numbers;
                }

                return undefined;
            }
            //Formatting is done from view to model (e.g. when you set $scope.telephone)
            //Function to insert hyphens if 10 digits were entered.
            var phoneFormat = function (value) {
                var numbers = value && value.replace(/-/g,"");
                var matches = numbers && numbers.match(/^(\d{3})(\d{3})(\d{4})$/);

                if (matches) {
                    return matches[1] + "-" + matches[2] + "-" + matches[3];
                }

                return undefined;
            }

           //Add these functions to the formatter and parser pipelines
           ngModelCtrl.$parsers.push(phoneParse);
           ngModelCtrl.$formatters.push(phoneFormat);

           //Since you want to update the error message on blur, call $setValidity on blur
           element.bind("blur", function () {
                var value = phoneFormat(element.val());
                var isValid = !!value;
                if (isValid) {
                    ngModelCtrl.$setViewValue(value);
                    ngModelCtrl.$render();
                }

                ngModelCtrl.$setValidity("telephone", isValid);
                //call scope.$apply() since blur event happens "outside of angular"
                scope.$apply();
            });
        }
    };
});

Working fiddle. This was just a quick way of demonstrating the parser and formatter pipelines that are used in ngModel, along with $setValidity -- which is used to populate the $error field(s).

Update: To use this same phone validation across multiple phones, use form with $error. Notice that each input gets a unique name that is used with myForm (name of form). Both use $error.telephone:

<form name="myForm">
    Mobile Phone:
    <input type="text" ng-model="mobilephone" phoneformat name="mobilephone" />
    <span class="error" ng-show="myForm.mobilephone.$error.telephone">
       Exact 10 Numbers only!
    </span>
    <br />
    Home Phone:
    <input type="text" ng-model="homephone" phoneformat  name="homephone" />
    <span class="error" ng-show="myForm.homephone.$error.telephone">
        Exact 10 Numbers only!
    </span>
</form>

Updated fiddle.

Patrick
  • 6,828
  • 3
  • 23
  • 31
  • I want to use this directive in different pages/forms/tabs so I want to get rid of hard coded "telephone" field in the statement "ngModelCtrl.$setValidity("telephone", isValid);".If I replace "telephone" with "phoneformat"(directive name) and it's not working as expected.Please help – user2580179 Sep 23 '14 at 14:48
  • The directive is specifically for phones. Why would you want it to say something different than "telephone" for error? If you want to make similar directives (e.g. to validate zip code), you have the template above and you can validate however you need for other field requirements... The post above answers your posted question. – Patrick Sep 23 '14 at 17:31
  • Example updated to have quick 5 number zip as well: http://jsfiddle.net/4xbv0tgL/18/ -- This is obviously not production zip validation, but a quick example to show how different directives can be used for validation. To take it a step further, you could make a helper function to return the linking function for you where you can pass it formatter and parser functions, but that might be overkill. – Patrick Sep 23 '14 at 17:43
  • I also noticed in your http://jsfiddle.net/4xbv0tgL/17/ that you are still looking at $error.telephone in your template. If you change it to "phoneformat" you have to update your template to be $error.phoneformat. – Patrick Sep 23 '14 at 17:48
  • I just updated fiddle with ng-model=mobilephone and want use this directive [link] http://jsfiddle.net/4xbv0tgL/25/ and when I enter more than 10 digits,it's throwing error? basically this directive I wantto user for homephone,mobilephone etc,so ng-model will be different in each case.so how to this directive? – user2580179 Sep 23 '14 at 21:27