Allow commas and decimal points in input field AngularJS - angularjs

I've come across an AngularJS filter than changes numeric values in a input field into a formatted number i.e 2500 becomes 2,500 and when applied to the modal it parses as an integer.
I was wonder if it was possible to add decimal points and keep the formatting for the user so 2500.24 becomes 2,500.24.
The script is as below:
angular.directive('format', function ($filter) {
'use strict';
return {
require: '?ngModel',
link: function (scope, elem, attrs, ctrl) {
if (!ctrl) {
return;
}
ctrl.$formatters.unshift(function () {
return $filter('currency')(ctrl.$modelValue, '', 2);
});
ctrl.$parsers.unshift(function (viewValue) {
var plainNumber = viewValue.replace(/[\,]/g, ''),
b = $filter('currency')(plainNumber, '', 2);
elem.val(b);
return plainNumber;
});
}
};
});
And the pattern I use is:
<input format pattern="[0-9]+([\.,][0-9]+)*" />

You can use the plugin ng-currency-mask.
https://github.com/vtex/ng-currency-mask
var app = angular.module('app', ['vtex.ngCurrencyMask']);
<input type="text" name="value" placeholder="0.00" ng-model="value" currency-mask />

Related

How to disable special characters in angular Js input tag. Only allow alphanumeric(PAN Card Validation Regex)

How to disable special characters in angular js input tag. Only allow alphanumeric
just like we use
<input type="text" ng-trim="false" style="text-transform: uppercase" ng-pattern="/^[a-zA-Z0-9]*$/" class="form-text" id="pan_card_number" name="pan_card_number" ng-minlength="10" maxlength="10" required ng-model="registration.newTSP.panCardNumber">
you can use Regex with Ng-pattern and Display the message through ng-message
$scope.useOnlySpecialCharacters = /^[a-zA-Z0-9]*$/;
<input type="text" ng-model="specialcharacters"
ng-pattern="useOnlySpecialCharacters" />
show message through ng-message
<div ng-message="pattern"> Please Enter AlphaNumeric </div>
OR
Best Option is to use Directives
app.directive('noSpecialChar', function () {
return {
require: 'ngModel',
restrict: 'A',
link: function (scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function (inputValue) {
if (inputValue == null) {
return '';
}
var cleanInputValue = inputValue.replace(/[^\w\s]/gi, '');
if (cleanInputValue != inputValue) {
modelCtrl.$setViewValue(cleanInputValue);
modelCtrl.$render();
}
return cleanInputValue;
});
}
}
});
LINK
use ng-pattern="/[A-Z]{5}\d{4}[A-Z]{1}/i" in your HTML input tag
use the following
Controller
$scope.panCardRegex = '/[A-Z]{5}\d{4}[A-Z]{1}/i';
HTML
<input type="text" ng-model="abc" ng-pattern="panCardRegex" />
Use Directives to restrict Special characters:
angular.module('scPatternExample', [])
.controller('scController', ['$scope', function($scope) {
}])
.directive('restrictSpecialCharactersDirective', function() {
function link(scope, elem, attrs, ngModel) {
ngModel.$parsers.push(function(viewValue) {
var reg = /^[a-zA-Z0-9]*$/;
if (viewValue.match(reg)) {
return viewValue;
}
var transformedValue = ngModel.$modelValue;
ngModel.$setViewValue(transformedValue);
ngModel.$render();
return transformedValue;
});
}
return {
restrict: 'A',
require: 'ngModel',
link: link
};
});
<input type="text" ng-model="coupon.code" restrict-Special-Characters-Directive>
set pattern to allow only alphanumeric
/^[a-z0-9]+$/i

Angular filter not working

I am coding a filter that will format phone numbers in a contact form I've built however for some reason the value in the input is never being updated and I'm not sure what I'm doing wrong.
Here's my HTML:
<div class='form-group'>
<input name='phone' ng-model='home.contact.phone' placeholder='(Area code) Phone' required ng-bind='home.contact.phone | phone' />
</div>
and here's my filter:
(function () {
'use strict'
angular
.module('Allay.phoneFilter', [])
.filter('phone', function () {
return function (phone) {
if(!phone) return '';
var res = phone + '::' // Since this isn't working, I'm doing something super simple, adding a double colon to the end of the phone number.
return res;
}
});
})();
I'm not sure if you need this, but here's the controller:
(function () {
'use strict'
angular
.module('Allay', [
'Allay.phoneFilter'
])
.controller('HomeController', function () {
var home = this;
});
})();
If I add an alert(res) before 'return res' in the filter I see the value I expect '123::', however the value in the input it's self is still just 123.
You need create directive to change your ngModel, like this:
.directive('phoneFormat', function() {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ctrl) {
var setvalue = function() {
elem.val(ctrl.$modelValue + "::");
};
ctrl.$parsers.push(function(v) {
return v.replace(/::/, '');
})
ctrl.$render = function() {
setvalue();
}
elem.bind('change', function() {
setvalue();
})
}
};
});
Use in html:
<input name='phone' ng-model='contact.phone' placeholder='(Area code) Phone' required phone-format />
JS Fiddle: http://jsfiddle.net/57czd36L/1/
Your usage of ngBind on the input is not quite correct. From the documentation,
The ngBind attribute tells Angular to replace the text content of the specified HTML element with the value of a given expression, and to update the text content when the value of that expression changes
You do not need to replace the text content of the <input> element, that wouldn't make sense. You can instead extend the formatter pipeline of the NgModelController using a directive like
app.directive('phoneFormat', function () {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$formatters.push(function (value) {
if (value)
return value + '::';
});
}
}
});
Then, in your HTML,
<input ng-model='home.contact.phone' phone-format />
In case you wanted to keep the filter you wrote (for other usages), you can actually re-use it in the directive like
app.directive('phoneFormat', [ '$filter', function ($filter) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
ngModel.$formatters.push($filter('phone'));
}
}
}]);
$filter('phone') simply returns the filter function registered under 'phone'. Here is a Plunker.
Note, this solution will only format data when you change the $modelValue of the NgModelController, for example like
$scope.$apply('home.contact.phone = "123-456-7890"');
If you are looking for something to update/format the value of the input as the user is typing, this is a more complicated task. I recommend using something like angular-ui/ui-mask.
Although a filter module is a good approach, I use an 'A' directive to do the dirty work because changing the element value will affect its ng-model.
However, I would only suggest this kind of solution if your actual data manipulation could sum in 3-4 lines of code; otherwise, a more thorough approach is needed.
This is an example that will delete anything which isn't an integer:
(function () {
'use strict'
angular.module('Allay').directive('phoneValidator', function () {
return {
restrict: 'A',
link: function(scope, element, attrs) {
angular.element(element).on('keyup', function() {
element.val(element.val().replace(/[^0-9\.]/, ''));
});
}
}
});
})();
And than in your HTML template :
<input name="phone" ng-model="home.contact.phone" placeholder="(Area code) Phone" phoneValidator required/>`
You should remove your "ng-bind" cause you are filtering it and what is presented is what in the ng-model. use value instead.
<input name='phone' ng-model='home.contact.phone | phone' value="{{contact.phone | phone}}" />
see working example: JsFiddle

Directive doesn't update scope variable

I have a directive that formats a phone number to (xxx) xxx-xxxx. The formatting works as expected, however, the model on the input field isn't updating unless you enter one character passed the standard 10. So after the user enters 10 digits the number automatically formats inside of the input field. But the scope variable set on ng-model does not save the formatting unless you enter an additional character.
Here's the directive:
(function (app) {
'use strict';
app.directive('formatPhone', [
function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, elem) {
elem.on('keyup', function() {
var origVal = elem.val().replace(/[^\d]/g, '');
if(origVal.length === 10) {
var str = origVal.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
var phone = str.slice(0, -1) + str.slice(-1);
jQuery('#phonenumber').val(phone);
}
});
}
};
}
]);
}(window.app));
And here is the input field, using the directive as an attribute:
<input type="text" placeholder="Phone" name="phone" id="phonenumber" class="user-search-input create-short form-control" ng-model="userCtrl.userPost.user.phoneNumber" required format-phone>
I've tried adding a $watch to it, also with no luck.
Try like
.directive('formatPhone', [
function() {
return {
require: 'ngModel',
restrict: 'A',
priority:999999, //<-- Give a higher priority
scope: {
model:'=ngModel' //<-- A 2 way binding to read actual bound value not the ngModel view value
},
link: function(scope, elem, attrs, ctrl) {
var unwatch = scope.$watch('model', function(val){
if(!val) return;
var origVal = val.replace(/[^\d]/g, '');
if(origVal.length === 10) {
var str = origVal.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
var phone = str.slice(0, -1) + str.slice(-1);
ctrl.$setViewValue(phone);
ctrl.$render();
unwatch();
}
});
}
};
}
]);

How can you limit the value from input using AngularJS?

I am looking for ways to limit the value inside the input to 4 and process the 4 digit value unto my controller.
<input type="number" class="form-control input-lg"
ng-model="search.main" placeholder="enter first 4 digits: 09XX">
{{ search.main | limitTo:4}}
Can always make a directive for it:
app.directive("limitTo", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.limitTo);
angular.element(elem).on("keypress", function(e) {
if (this.value.length == limit) e.preventDefault();
});
}
}
}]);
<input limit-to="4" type="number" class="form-control input-lg" ng-model="search.main" placeholder="enter first 4 digits: 09XX">
You can always use ng-minlength, ng-maxlength for string length and min, max for number limits. Try this
<input type="number"
name="input"
class="form-control input-lg"
ng-model="search.main"
placeholder="enter first 4 digits: 09XX"
ng-minlength="1"
ng-maxlength="4"
min="1"
max="9999">
DEMO FIDDLE
No need to use an AngularJS directive.
Just use the good old standard html attribute maxlength.
<input type="text" maxlength="30" />
I used the accepted answer as a launching point, but this is what I came up with.
angular.module('beastTimerApp')
.directive('awLimitLength', function () {
return {
restrict: "A",
require: 'ngModel',
link: function (scope, element, attrs, ngModel) {
attrs.$set("ngTrim", "false");
var limitLength = parseInt(attrs.awLimitLength, 10);// console.log(attrs);
scope.$watch(attrs.ngModel, function(newValue) {
if(ngModel.$viewValue.length>limitLength){
ngModel.$setViewValue( ngModel.$viewValue.substring(0, limitLength ) );
ngModel.$render();
}
});
}
};
});
usage
<input name="name" type="text" ng-model="nameVar" aw-limit-length="10"/>
The key is to use $setViewValue() and $render() to set and display the changes respectively. This will make sure $viewValue and $modelValue are correct and displayed properly. You also want to set ngTrim to false to prevent the user adding whitespaces beyond the limit. This answer is an amalgamation of #tymeJV's answer and this blog post... https://justforchangesake.wordpress.com/2015/01/10/useful-angularjs-directives/
Will do it allowing backspaces and deletes.
app.directive("limitTo", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.limitTo);
angular.element(elem).on("keydown", function() {
if(event.keyCode > 47 && event.keyCode < 127) {
if (this.value.length == limit)
return false;
}
});
}
}
}]);
you can use this code:
<input type="number" class="form-control input-lg"
ng-model="search.main"
ng-keypress="limitKeypress($event,search.main,4)"
placeholder="enter first 4 digits: 09XX">
and AngularJS code:
$scope.limitKeypress = function ($event, value, maxLength) {
if (value != undefined && value.toString().length >= maxLength) {
$event.preventDefault();
}
}
We can use ng-value instead:
ng-value="(minutes > 60 ? minutes = 0 : minutes)"
In html code:
<input type="text" class="form-control" ng-model="minutes" ng-maxlength="2" ng-pattern="/^[0-9]*$/" ng-value="(minutes > 60 ? minutes = 0 : minutes)"/>
This will check for the value and if it is greater than 60, it replaces the value with 0.
As there is a problem in above directive (answer of tymeJV). If you enter maximum length once, then it will not accept any other character even the backspace. That is if limit-to="4" and if you entered 4 character in input box, then you will not able to delete it. SO here is the updated answer.
app.directive("limitTo", [function () {
return {
restrict: "A",
link: function (scope, elem, attrs) {
var limit = parseInt(attrs.limitTo);
elem.bind('keypress', function (e) {
// console.log(e.charCode)
if (elem[0].value.length >= limit) {
console.log(e.charCode)
e.preventDefault();
return false;
}
});
}
}
}]);
Angular material has a directive mdMaxlength, if you want to cut off the input at this length, you can use this directive:
app.directive("forceMaxlength", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.mdMaxlength);
angular.element(elem).on("keydown", function() {
if (this.value.length >= limit) {
this.value = this.value.substr(0,limit-1);
return false;
}
});
}
}
}]);
Usage:
<input type="text" md-maxlength="30" force-maxlength=""/>
We can write the directive to listen to the keypress event. But for some old browsers, this event is not triggered. Thats why i created a directive in such a way that there's no dependency on browser specific events limitation.
I created an angular directive to limit the number of text in the input box.
'use strict';
angular.module("appName")
.directive("limitTo", [function() {
return {
restrict: "A",
require: "ngModel",
link: function(scope, elem, attrs, ctrl) {
var limit = parseInt(attrs.limitTo);
ctrl.$parsers.push(function (value) {
if (value.length > limit){
value = value.substr(0, limit);
ctrl.$setViewValue(value);
ctrl.$render();
}
return value;
});
}
}}]);
Usage: <input limit-to="3" ng-model="test"/> would allow only 3 characters in input box.
In Angular Js Material we can limit input field by "maxLimit", for example we need limit of input text should b 60 character as:
maxLimit ='60'
complete code:
<form-input-field flex
class="input-style-1"
title="Quick response tag title"
placeholder="Write a catchy title to help users get more information on the service card"
form-name="parent.qrtForm"
show-error="showError"
name="title"
maxLength="65"
text-limit="65"
required="true"
ng-model="newQrt.tagName">
Run this operation on any change to the number:
var log = Math.log(number) / Math.log(10);
if (log >= 4)
number = Math.floor(number / Math.pow(10, Math.ceil(log - 4)));
This will always limit "number" to 4 digits.
I am reiterating what #Danilo Kobold said.
I had to make sure that users can enter only numbers (0-9) [Without 'e' or '.' or '-'] and a limit of 4 values only.
app.directive("limitTo", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.limitTo);
var exclude = /Backspace|Enter/;
angular.element(elem).on("keydown", function(e) {
if (event.keyCode > 47 && event.keyCode < 58) {
if (this.value.length == limit) e.preventDefault();
} else if (!exclude.test(event.key)) {
e.preventDefault();
}
});
}
}
}]);
If you want to use only limit then use
app.directive("limitTo", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.limitTo);
var exclude = /Backspace|Enter/;
angular.element(elem).on("keydown", function(e) {
if (!exclude.test(event.key)) {
if (this.value.length == limit) e.preventDefault();
}
});
}
}
}]);
You can add more keys if you want to the exclude variable, like this:
var exclude = /Backspace|Enter|Tab|Delete|Del|ArrowUp|Up|ArrowDown|Down|ArrowLeft|Left|ArrowRight|Right/;
Got idea from this post
Hope I helped someone.
You can just use
ui-mask="9999"
as attribute in your view.
**
app.directive("limitTo", [function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.limitTo);
var exclude = /Backspace|Enter/;
angular.element(elem).on("keydown", function(e) {
if (e.keyCode > 47 && e.keyCode < 58) {
if (this.value.length == limit) e.preventDefault();
} else if (!exclude.test(e.key)) {
e.preventDefault();
}
});
}
}
}]);
**
Use this directive if you want to restrict max length for a input field which is present as part of custom directive template. This is the native html5 way of restricting max-lenth. This will also handle the copy paste case also to restrict till the maxlength on pasting.
app.directive('inputWrapper', function() {
return {
restrict: 'A',
template: "<input type='text'/>"
};
});
app.directive('maxInputLength', function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
var limit = parseInt(attrs.maxInputLength);
angular.element(elem).find('input').attr('maxlength', limit);
}
};
});
<input-wrapper max-input-lenth="35"></input-wrapper>
Do this instead
<input type="text" class="form-control input-lg" ng-model="search.main" placeholder="enter first 4 digits: 09XX" maxlength="4" num-only>{{ search.main | limitTo:4}}
use the type "text", then use maxlength to limit it and also use the num-only option to make it number input only

Angular, input field with a currency mask directive for money format on the fly

I'm trying to create an input mask for a EU money field using http://jquerypriceformat.com/
So far in my directive, the input shows correctly to the user with the mask applied, but I believe there's something wrong, because the POST values are being sent with weird formatting, totally different than what we see in the input field.
I include the priceformat.js
<script src="js/jquery.price_format.1.8.min.js"></script>
<input type="text" currency-input ng-model...>
And on angular:
app.directive('currencyInput', function() {
return {
require: '?ngModel',
link: function($scope, element, attrs, controller) {
element.priceFormat({
prefix: '',
centsSeparator: ',',
thousandsSeparator: '.'
});
}
};
});
My input shows the value with the mask correctly, but on POST data (called by angular) it's a different value, what am I missing?
input > 2.200,80 | post > 22,0080
Thanks
From your example I don't see that link returns something.
I would write directive something like:
.directive('format', ['$filter', function ($filter) {
return {
require: '?ngModel',
link: function (scope, elem, attrs, ctrl) {
if (!ctrl) return;
ctrl.$formatters.unshift(function (a) {
return $filter(attrs.format)(ctrl.$modelValue)
});
ctrl.$parsers.unshift(function (viewValue) {
elem.priceFormat({
prefix: '',
centsSeparator: ',',
thousandsSeparator: '.'
});
return elem[0].value;
});
}
};
}]);
Demo 1 Fiddle
If you want on start fire the filter, use $formatters:
Now link is:
link: function (scope, elem, attrs, ctrl) {
if (!ctrl) return;
var format = {
prefix: '',
centsSeparator: ',',
thousandsSeparator: ''
};
ctrl.$parsers.unshift(function (value) {
elem.priceFormat(format);
return elem[0].value;
});
ctrl.$formatters.unshift(function (value) {
elem[0].value = ctrl.$modelValue * 100 ;
elem.priceFormat(format);
return elem[0].value;
})
}
Demo 2 Fiddle
Push a $parser to the controller, and only update the value when it doesn't match the input using $setViewValue() and $render().
app.directive('currencyInput', function() {
return {
require: '?ngModel',
link: function($scope, element, attrs, controller) {
return ctrl.$parsers.push(function(inputValue) {
...
if (result != inputValue) {
controller.$setViewValue(res);
controller.$render();
}
});
}
};
});
Here's a fiddle with the logic I used for my currency input directive: Fiddle
Late to the party, but I believe this deserves another answer! I've been using the ng-currency module. It's absolutely fantastic.
I like Dubilla's approach cause of its simplicity and elegance. I decided to add (with due credits) some features on top of it to make it quite close to real world use case.
I've using it on a github project to create some useful finance directives github.
Notable extra features:
It does some rigorous checking of the inputs to give a valid response.
It has some keyboard shortcuts to make entering large numbers quicker.
I show how to integrate it with bootstrap and ngmodel css updates.
As a bonus I outputed the form's ngmonel as JSON to help people see how the form validation works in real time
It also uses a POJO as the ngmodel:
function Money() {
this.notional = 0;
this.maxValue = 99999999999.9;
this.maxValueString = "99,999,999,999.9";
this.maxPrecision = 10;
}
you can use it with Bootstrap 3 like so:
<h1>Currency Formatting directive</h1>
<div class="row">
<div class="col-md-6">
<form name="myForm">
<div class="form-group" ng-class="{'has-error': myForm.notional.$invalid && myForm.notional.$touched}">
<input type="text" ng-model="myForm.money.notional " money="money" money-input size="30" required
name="notional"
class="form-control"
placeholder="Enter notional amount"/>
<p class="help-block error" ng-show="myForm.notional.$error.required && myForm.notional.$touched">Required</p>
</div>
<button ng-disabled="myForm.$invalid" type="submit">SAVE</button>
</form>
<h2>Tips</h2>
<ol>
<li> Entering 'k' will multiply the amount by one thousand</li>
<li> Entering 'm' will multiply the amount by one million</li>
<li> Entering 'b' will multiply the amount by one billion</li>
</ol>
</div>
</div>
<p>Form debugger</p>
<pre>
form = {{ myForm | json }}
</pre>
Here's a way to handle this without jQuery using only an Angular directive. This example doesn't support decimals. It's easy to modify it to support that though, just change the $filter in the toView() function.
In my opinion this is a better approach to solve the same problem, as you can avoid loading in jQuery and the currency plugin mentioned by the author. Locale support for Euro should be supported by the use the $locale properties, but I've only tested this for use in USD.
(function() {
var app = angular.module('currencyMask', []);
// Controller
app.controller('ctrl', ['$scope', function($scope) {
$scope.amount = 100000;
}]);
// Directive
app.directive('inputCurrency', ['$locale', '$filter', function($locale, $filter) {
// For input validation
var isValid = function(val) {
return angular.isNumber(val) && !isNaN(val);
};
// Helper for creating RegExp's
var toRegExp = function(val) {
var escaped = val.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
return new RegExp(escaped, 'g');
};
// Saved to your $scope/model
var toModel = function(val) {
// Locale currency support
var decimal = toRegExp($locale.NUMBER_FORMATS.DECIMAL_SEP);
var group = toRegExp($locale.NUMBER_FORMATS.GROUP_SEP);
var currency = toRegExp($locale.NUMBER_FORMATS.CURRENCY_SYM);
// Strip currency related characters from string
val = val.replace(decimal, '').replace(group, '').replace(currency, '').trim();
return parseInt(val, 10);
};
// Displayed in the input to users
var toView = function(val) {
return $filter('currency')(val, '$', 0);
};
// Link to DOM
var link = function($scope, $element, $attrs, $ngModel) {
$ngModel.$formatters.push(toView);
$ngModel.$parsers.push(toModel);
$ngModel.$validators.currency = isValid;
$element.on('keyup', function() {
$ngModel.$viewValue = toView($ngModel.$modelValue);
$ngModel.$render();
});
};
return {
restrict: 'A',
require: 'ngModel',
link: link
};
}]);
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
<div ng-app="currencyMask" ng-controller="ctrl">
<input input-currency ng-model="amount">
<p><strong>Amount:</strong> {{ amount }}</p>
</div>

Resources