Reputation: 32400
I have read questions and answers here on StackOverflow about how to use "formatters" and "parsers" to allow the user to enter a value into an input, and then have that input transformed in the model.
I have a slightly different requirement.
I wish to both help and force the user to enter input in a certain format. In other words, both the display and the model should match exactly, but the user should be restricted to entering data in the specified format.
To use a common example, I want the user to enter a ten-digit phone number in the following format:
(xxx)xxx-xxxx
Coming from a jQuery background, I know that I can attach an event to the "change" event handler for the input and perform string manipulation to look for ten digits in the input and either format them as specified or show the user an error if there aren't exactly ten digits in the number.
I am also aware that I can use Angular to put restrictions on the input so that the form won't submit unless the format of the input matches the specification. This has the major disadvantage that the user may fill out the whole form that then be told to make a change to a previous field, breaking the user's workflow.
I want to go a step further and automatically format the number as soon as it is keyed in. What features of Angular are most appropriate for this task?
Use case: the user enters "9006345789". The code should, either as the user types the number, or as the user moves focus away from the input, replace "9006345789" with "(900)634-5789". The result should be the same if the user enters "900-634-5789" or "900.634.5789" or any other input with exactly ten digits.
Please bear in mind that the phone number example is one of many formatting examples and I would like my code to be reusable.
Upvotes: 0
Views: 589
Reputation: 4370
Actually, we can format the numbers with the use of Angularjs and i have attached the working link below.
var myApp = angular.module('myApp', []);
myApp.controller('MyCtrl', function($scope) {
$scope.currencyVal;
}).directive('phoneInput', function($filter, $browser) {
return {
require: 'ngModel',
link: function($scope, $element, $attrs, ngModelCtrl) {
var listener = function() {
var value = $element.val().replace(/[^0-9]/g, '');
$element.val($filter('tel')(value, false));
};
// This runs when we update the text field
ngModelCtrl.$parsers.push(function(viewValue) {
return viewValue.replace(/[^0-9]/g, '').slice(0, 10);
});
ngModelCtrl.$render = function() {
$element.val($filter('tel')(ngModelCtrl.$viewValue, false));
};
$element.bind('change', listener);
$element.bind('keydown', function(event) {
var key = event.keyCode;
if (key == 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) {
return;
}
$browser.defer(listener);
});
$element.bind('paste cut', function() {
$browser.defer(listener);
});
}
};
});
myApp.filter('tel', function() {
return function(tel) {
console.log(tel);
if (!tel) {
return '';
}
var value = tel.toString().trim().replace(/^\+/, '');
if (value.match(/[^0-9]/)) {
return tel;
}
var country, city, number;
switch (value.length) {
case 1:
case 2:
case 3:
city = value;
break;
default:
city = value.slice(0, 3);
number = value.slice(3);
}
if (number) {
if (number.length > 3) {
number = number.slice(0, 3) + '-' + number.slice(3, 7);
} else {
number = number;
}
return ("(" + city + ") " + number).trim();
} else {
return "(" + city;
}
};
});
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<link rel="stylesheet" href="style.css">
<script src="script.js"></script>
</head>
<body>
<div class="body" ng-app="myApp">
<div class="wrapper" ng-controller="MyCtrl">
<div class="info">PHONE: {{phoneVal | tel}}</div>
<input class="input-phone" type='text' phone-input ng-model="phoneVal" />
</div>
</div>
</body>
</html>
Hope it helps you :)
Upvotes: 1