Allow only numbers in range to be entered into text box - javascript

I'm trying to create input text directive that'll only accept numbers within a specific range. I've tried parsing the value as an integer, of course min and max didn't work.
I do not want to use input[type="number"].
Ultimately, I'm trying to create a date of birth free input text field.
Like the one seen below:
The directive I've adapted [which i'm trying to use at the moment] - the original can be found # angularjs: allows only numbers to be typed into a text box
app.directive('onlyDigits', function () {
return {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function (inputValue) {
if (inputValue == undefined) return '';
var transformedInput = inputValue.replace(/[^0-9]/g, '');
var theInt = parseInt(transformedInput);
if (transformedInput !== inputValue) {
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}
return theInt;
});
}
};
What I hoped to do after I've solved this, is to do a conditional ng-show, to show an error for a span element - when the user has typed a value over 31 (for day) 12 (for month) and so forth.
I welcome any suggestions.
Thank you.

I had the exact same problem. I tried "everything" to make it both user friendly and to not accept invalid values. Finally I gave up on apparently easy solutions, like ng-pattern, and with help of a friend #Teemu Turkia, we came up with integers-only directive.
It uses type="text", supports both min and max, do not accept chars beyond numbers and - (as a first character in case minimum is negative) to be typed.
Also, ng-model is never assigned with invalid value such as empty string or NaN, only values between given range or null.
I know, at first it looks rather intimidating ;)
HTML
// note: uses underscore.js
<body>
<form name="form">
<header>DD / MM / YYYY</header>
<section>
<input type="text"
name="day"
ng-model="day"
min="1"
max="31"
integers-only>
<input type="text"
name="month"
ng-model="month"
min="1"
max="12"
integers-only>
<input type="text"
name="year"
ng-model="year"
min="1900"
max="2016"
integers-only>
</section>
<section>
<span ng-show="form.day.$invalid">Invalid day</span>
<span ng-show="form.month.$invalid">Invalid month</span>
<span ng-show="form.year.$invalid">Invalid year</span>
</section>
</form>
</body>
JavaScript
/**
* numeric input
* <input type="text" name="name" ng-model="model" min="0" max="100" integers-only>
*/
angular.module('app', [])
.directive('integersOnly', function() {
return {
restrict: 'A',
require: 'ngModel',
scope: {
min: '=',
max: '='
},
link: function(scope, element, attrs, modelCtrl) {
function isInvalid(value) {
return (value === null || typeof value === 'undefined' || !value.length);
}
function replace(value) {
if (isInvalid(value)) {
return null;
}
var newValue = [];
var chrs = value.split('');
var allowedChars = ['0','1','2','3','4','5','6','7','8','9','-'];
for (var index = 0; index < chrs.length; index++) {
if (_.contains(allowedChars, chrs[index])) {
if (index > 0 && chrs[index] === '-') {
break;
}
newValue.push(chrs[index]);
}
}
return newValue.join('') || null;
}
modelCtrl.$parsers.push(function(value) {
var originalValue = value;
value = replace(value);
if (value !== originalValue) {
modelCtrl.$setViewValue(value);
modelCtrl.$render();
}
return value && isFinite(value) ? parseInt(value) : value;
});
modelCtrl.$formatters.push(function(value) {
if (value === null || typeof value === 'undefined') {
return null;
}
return parseInt(value);
});
modelCtrl.$validators.min = function(modelValue) {
if (scope.min !== null && modelValue !== null && modelValue < scope.min) { return false; }
return true;
};
modelCtrl.$validators.max = function(modelValue) {
if (scope.max !== null && modelValue !== null && modelValue > scope.max) { return false; }
return true;
};
modelCtrl.$validators.hasOnlyChar = function(modelValue) {
if (!isInvalid(modelValue) && modelValue === '-') { return false; }
return true;
};
}
};
});
Result
Related plunker here http://plnkr.co/edit/mIiKuw

Here is solution without any custom directives. It's still input type="number" but needed functionality is achieved.
Here is plunker
<!DOCTYPE html>
<html>
<head></head>
<body ng-app="app" ng-controller="dobController as dob">
<h3>Date of birth form</h3>
<form name="dobForm" class="form" novalidate="">
<div>
<label for="date">DD</label>
<input type="number" ng-model="dob.date" name="date" min="1" max="31" integer />
<label for="month">MM</label>
<input type="number" ng-model="dob.month" name="month" min="1" max="12" integer />
<label for="year">YYYY</label>
<input type="number" ng-model="dob.year" name="year" min="1900" max="2016" integer />
<div style="color: red;" ng-if="dobForm.$invalid">
<p ng-show="dobForm.date.$error.min || dobForm.date.$error.max">
date must be in range 1 to 31!
</p>
<p ng-show="dobForm.month.$error.min || dobForm.month.$error.max">
month must be in range 1 to 12!
</p>
<p ng-show="dobForm.year.$error.min || dobForm.year.$error.max">
year must be in range 1900 to 2016!
</p>
</div>
</div>
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular-messages.js"></script>
<script>
var app = angular.module('app', []);
app.controller('dobController', function($scope) {});
</script>
<style>
input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
</style>
</body>
</html>

This solution uses the min and max attributes to limit values of the input fields. It also uses ngModelOptions to update the model value only after a defined interval. This is to allow users to type in values before the model parser acts on the input.
angular.module("app", []);
angular.module("app").directive('onlyDigits', function() {
return {
restrict: 'A',
require: '?ngModel',
scope: {
min: "#",
max: "#"
},
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(inputValue) {
if (inputValue == undefined) return '';
var transformedInput = inputValue.replace(/[^0-9]/g, '');
var theInt = parseInt(transformedInput);
var max = scope.max;
var min = scope.min;
if (theInt > max) {
theInt = max;
} else if (theInt < min) {
theInt = min;
}
modelCtrl.$setViewValue(theInt.toString());
modelCtrl.$render();
return theInt;
});
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<body ng-app="app">
<input type="text" ng-model="month" ng-model-options="{ debounce: 200 }" only-digits min="1" max="12">
<input type="text" ng-model="day" ng-model-options="{ debounce: 200 }" min="1" max="30" only-digits>
<input type="text" ng-model="year" ng-model-options="{ debounce: 500 }" only-digits min="1900" max="2050">
</body>

Related

Updating AngularJS model with ng-change causes one field to become null when updating

Updating AngularJS model values simultaneously on 3 separate fields causes one field to become null on ng-change.
I'm getting some strange behavior with ng-change. What I have is 3 separate fields that all integrate together. One is for a base loan amount, one is for an estimated value of a property and the last one is the loan to value ratio. When entering a value for base loan amount and for estimated value the loan to value ratio is calculated. Then if the user decides to change the loan to value ratio the base loan amount and/or estimated value is recalculated and so on.
The logic that I have so far works as expected. I enter a base loan amount, then enter an estimated value and then the loan to value ratio is calculated. However, as soon as the value is calculated the base loan amount field then empties and becomes null.
I'm not sure why this is happening and I've tried both ng-blur and ng-change and I get the same result. I've debugged this in Chrome for what seems like hours.
I've provided the html that I'm using and the logic for the operation in my controller.
Thank you
Here is Plunker with my code
HTML Content
<div class="form-content">
<form name="priceSearch" novalidate>
<!-- Row 1 -->
<div class="form-row">
<!-- The LTV (Loan-To-Value) ratio is calculated as the amount of the mortgage lien divided by the appraised value of the property, expressed as a percentage. -->
<div class="form-group col-md-3">
<!--if user enters loan amount, update LTV-->
<label for="baseLoanAmt">Base Loan Amount</label>
<input name="baseLoanAmt" class="form-control form-control-sm" type="number" placeholder="0.00" ng-step="any" ng-model="pricer.baseLoanAmount" ng-required="true" aria-describedby="blaHelpInline" ng-change="updateBaseLoanAmtEstValLTV('baseLoanAmt', pricer.baseLoanAmount)" ng-model-options="{debounce: {default: 400, blur: 0}}">
</div>
<div class="form-group col-md-3">
<label for="estimatedVal">Estimated Value</label>
<input name="estimatedVal" class="form-control form-control-sm" type="number" placeholder="0.00" step="any" ng-model="pricer.appraisedEstimatedValue" ng-required="true" aria-describedby="estValHelpInline" ng-change="updateBaseLoanAmtEstValLTV('estimatedVal', pricer.appraisedEstimatedValue)" ng-model-options="{debounce: {default: 400, blur: 0}}">
</div>
<div class="form-group col-md-3">
<!--if user enters LTV, update base loan amount-->
<label for="ltvRatio">LTV</label>
<input name="ltvRatio" class="form-control form-control-sm" type="number" ng-step="any" ng-model="pricer.ltvRatio" ng-change="updateBaseLoanAmtEstValLTV('ltvRatio', pricer.ltvRatio)" ng-model-options="{debounce: {default: 400, blur: 0}}" ng-pattern="/^\d+(\.\d{1,2})?$/">
</div>
<div class="form-group col-md-3">
<label>Loan Purpose</label>
<select class="form-control form-control-sm" ng-model="pricer.loanInformation.loanPurpose" ng-options="obj.val as obj.key for obj in loanPurposeOptions" ng-required="true">
</select>
</div>
</div>
<!-- End Row 1 -->
</form>
</div>
Controller Logic
app.controller('pricingSearch', ["$scope", "$rootScope", "$q", "dal", "$http", "$timeout", "$filter", function ($scope, $root, $q, _dal, $http, $timeout, $filter) {
// Precision Round function
function precisionRound(number, precision) {
var factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
}
$scope.pricer = {
"baseLoanAmount": 0,
"appraisedEstimatedValue": 0,
"ltvRatio": 0,
"fico": 700,
"debtToIncomeRatio": 15.0,
"waiveEscrows": false,
"loanType": "Conforming",
"loanTerms": {
"ThirtyYear": true
}
};
$scope.updateBaseLoanAmtEstValLTV = function (fieldName, value) {
var findBaseLoanAmtRatio = ($scope.pricer.appraisedEstimatedValue * $scope.pricer.ltvRatio) /10;
var findEstimatedValRatio = ($scope.pricer.baseLoanAmount * $scope.pricer.ltvRatio) / 10;
var findLtvRatio = ($scope.pricer.baseLoanAmount / $scope.pricer.appraisedEstimatedValue) * 10;
console.log('The fieldName is: ' + (fieldName));
console.log('The value is: ' + (value));
if (fieldName !== 'baseLoanAmt' && value != null) {
console.log('Fire 1');
$scope.pricer.baseLoanAmount = precisionRound(findBaseLoanAmtRatio, 2);
}
if (fieldName !== 'estimatedVal' && value != null) {
console.log('Fire 2');
$scope.pricer.appraisedEstimatedValue = precisionRound(findEstimatedValRatio, 2);
}
if (fieldName !== 'ltvRatio' && value != null) {
console.log('Fire 3');
$scope.pricer.ltvRatio = precisionRound(findLtvRatio, 3);
}
};
}]);
https://plnkr.co/edit/BFlvshCp1Rhs6WpxrjmN?p=preview
It's probably because at some points in your code you are dividing by zero.
You should never divide by a number until you first check that it is not a zero.
function calcLtv() {
var findLtvRatio;
if($scope.pricer.appraisedEstimatedValue === 0) {
findLtvRatio = 0;
}
else {
findLtvRatio = ($scope.pricer.baseLoanAmount / $scope.pricer.appraisedEstimatedValue) * 10;
}
return findLtvRatio;
}
Okay so I have solved the issues that I had. First I had to set up a system to tell angular that calculations were occurring and then the calculation had stopped.
Then I did some extra checks for the field values and ensure they were not dividing by zero. I also added some time for the calculations to complete so they were not finishing too quickly.
Thanks to Pop-A-Stash for pointing out the obvious to me.
The updated source can be found at this plunkr
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $timeout) {
// Precision Round function
function precisionRound(number, precision) {
var factor = Math.pow(10, precision);
return Math.round(number * factor) / factor;
}
$scope.pricer = {
"baseLoanAmount": 0,
"appraisedEstimatedValue": 0,
"ltvRatio": 0
};
$scope.recalculateLoanVals = function(fieldName, value) {
var findBaseLoanAmtRatio = $scope.pricer.appraisedEstimatedValue * $scope.pricer.ltvRatio;
var findEstimatedValRatio = $scope.pricer.baseLoanAmount * $scope.pricer.ltvRatio;
var findLtvRatio = $scope.pricer.baseLoanAmount / $scope.pricer.appraisedEstimatedValue;
if ($scope.calculating) {
// console.log('Calculating...');
// console.log('The field name is: ', fieldName);
// console.log('The value is: ', value);
if (($scope.pricer.baseLoanAmount > 0) && ($scope.pricer.appraisedEstimatedValue > 0) && (fieldName !== 'ltvRatio')) {
// console.log('Just baseLoanAmt and estimatedVal are not equal to zero');
// console.log('Calculating is: ', $scope.calculating);
$timeout(function() {
$scope.pricer.ltvRatio = precisionRound(findLtvRatio, 2);
}, 1000);
}
if (($scope.pricer.baseLoanAmount > 0) && ($scope.pricer.appraisedEstimatedValue > 0) && ($scope.pricer.ltvRatio > 0) && fieldName !== 'baseLoanAmt') {
// console.log('All three are not equal to zero');
$scope.pricer.ltvRatio = value;
$timeout(function() {
$scope.pricer.baseLoanAmount = precisionRound(findBaseLoanAmtRatio, 0);
}, 1000);
}
return;
}
$scope.calculating = true;
$timeout(function() {
// console.log('No longer calculating!');
$scope.calculating = false;
}, 1200);
};
});

angularjs directive for accept input numbers only in the given range

Hi I am developing web application in angularjs. I have requirement to validate textbox. It should accept only numbers with max 10 digits. I have directive but current directive should not restrict number of digits typed.
myapp.directive('validNumber', function () {
return {
require: '?ngModel',
link: function (scope, element, attrs, ngModelCtrl) {
if (!ngModelCtrl) {
return;
}
ngModelCtrl.$parsers.push(function (val) {
if (angular.isUndefined(val)) {
var val = '';
}
var clean = val.replace(/[^0-9]+/g, '');
if (val !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
element.bind('keypress', function (event) {
if (event.keyCode === 32) {
event.preventDefault();
}
});
}
};
});
<div class="inputblock" ng-class="{ 'has-error' : ((form1.$submitted && form1.idnumber.$invalid )|| (form1.idnumber.$invalid && form1.idnumber.$dirty))}">
<label class="inputblock-label" ng-show="idnumber">{{ 'ID Number' | translate }}</label>
<span class="ang-error" style="color:#fff" ng-show="form1.idnumber.$dirty && form1.idnumber.$invalid ">
<span ng-show="form1.idnumber.$invalid && form1.idnumber.$dirty">*{{'Max allowed digits 10' | translate}}</span>
</span>
<input class="with-icon" type="text" name="idnumber" placeholder="{{ 'ID Number' | translate }}" ng-model="idnumber" required ng-pattern="/^[0-9]{1,7}$/" > <!--valid-number-->
</div>
May i know what should be changed in the above directive so that it can accept maximum only 10 digits! Any help would be appreciated. Thank you.
Use the following code and try. my original purpose of this code was to limit the number to integer. But I have modified it a little so you can use this
(function() {
'use strict';
angular.module('app').directive('intValidate', intValidate);
function intValidate($locale) {
var decimalSep = $locale.NUMBER_FORMATS.DECIMAL_SEP;
var toNumberRegex = new RegExp('[^0-9\\' + decimalSep + ']', 'g');
function toNumber(currencyStr) {
return parseFloat(currencyStr.toString().replace(toNumberRegex, ''), 10);
}
return {
restrict : 'A',
require : 'ngModel',
link : function validate(scope, elem, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(newViewValue) {
var modelValue = toNumber(newViewValue);
var valid = modelValue <= 9999999999;
modelCtrl.$setValidity('limitcheck', valid);
return valid ? newViewValue : undefined;
});
}
};
}
})();
and use,
<input type="text" id="value" name="value" int-validate>
and if you want an error message
<p class="help-block" ng-if="cacc.form.value.$error.limitcheck">Max 10 digits allowed</p>

onchange event not accepting my javascript code

I have two text input for the user to type numbers, and I would like the page to output the total of these two numbers in another text input
<input id="attendance_1" onchange="parseInt(document.getElementById('attendance_output').value) += parseInt(this.value);" type="text" name="attendance_1" value="" />
<input id="attendance_2" onchange="parseInt(document.getElementById('attendance_output').value) += parseInt(this.value);" type="text" name="attendance_2" value="" />
// The results of adding the two text values should go here
<input id="attendance_output" type="text" value="" />
I get the error:
ReferenceError: invalid assignment left-hand side
I suggest putting the code of your onchange in a function and just calling that function onclick. It makes things way more easy to debug.
Example
function addValue(field) {
parseInt(document.getElementById('attendance_output').value) += parseInt(field.value);
}
<input id="attendance_1" onchange="addValue(this)" type="text" name="attendance_1" value="" />
<input id="attendance_2" onchange="parseInt(document.getElementById('attendance_output').value) += parseInt(this.value);" type="text" name="attendance_2" value="" />
// The results of adding the two text values should go here
<input id="attendance_output" type="text" value="" />
But the problem is, that your calculation is not assigned to anything. You take the field value, parse it and try to and a value to the parse result.
I guess you want to add that value to the field value and assign it?!
function addValue(field) {
var val = parseInt(document.getElementById('attendance_output').value);
val += parseInt(field.value);
document.getElementById('attendance_output').value = val;
}
Try below code. it should work.
your code is not working because += sign in expression.
<input id="attendance_1" onchange="document.getElementById('attendance_output').value=parseInt(document.getElementById('attendance_output').value) + parseInt(this.value);" type="text" name="attendance_1" value="" />
<input id="attendance_2" onchange="document.getElementById('attendance_output').value=parseInt(document.getElementById('attendance_output').value) + parseInt(this.value);" type="text" name="attendance_2" value="" />
// The results of adding the two text values should go here
<input id="attendance_output" type="text" value="" />
So this is really basic JS with typechecks
function addValue(field) {
parseInt(document.getElementById('attendance_output').value) += parseInt(field.value);
}
<input id="attendance_1" onchange="addValue(this)" type="text" name="attendance_1" value="" />
<input id="attendance_2" onchange="parseInt(document.getElementById('attendance_output').value) += parseInt(this.value);" type="text" name="attendance_2" value="" />
// The results of adding the two text values should go here
<input id="attendance_output" type="text" value="" />
But the problem is, that your calculation is not assigned to anything. You take the field value, parse it and try to and a value to the parse result.
I guess you want to add that value to the field value and assign it?!
function addValue(field) {
var oVal = parseInt(document.getElementById('attendance_output').value);
var iVal = parseInt(field.value);
if(!oVal || Number.isNaN(oVal)) {
oVal = 0;
}
if(!iVal || Number.isNaN(iVal)) {
iVal = 0;
}
oVal = oVal + iVal;
document.getElementById('attendance_output').value = oVal;
}
try this. :) it will not work properly if the user input string, so i think it should have validation.
function addValue() {
var num1 = document.getElementById('attendance_1').value;
var num2 = document.getElementById('attendance_2').value;
if (num1 === ''){
num1 = 0;
}
if(num2 === ''){
num2 = 0;
}
var sum = parseInt(num1) + parseInt(num2);
document.getElementById('attendance_output').value = sum;
}
you can make the textbox accept only numbers, by using jquery
$(document).ready(function() {
$("#attendance_1, #attendance_2").keydown(function (e) {
if ($.inArray(e.keyCode, [46, 8, 9, 27, 13, 110, 190]) !== -1 ||
(e.keyCode == 65 && ( e.ctrlKey === true || e.metaKey === true ) ) ||
(e.keyCode >= 35 && e.keyCode <= 40)) {
return;
}
if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
e.preventDefault();
}
});
});
Use this code inside
onchange="document.getElementById('attendance_output').value=+document.getElementById('attendance_output').value+ +this.value"
Hope it will be useful for you :)
This may be an option. I removed the inline JS completely. Went from onchange to an oninput handler, which will only do the calculation if the values given are actually numbers not strings.
var inpt = document.querySelectorAll('.attendance');
var out = document.getElementById('attendance_output');
var onInput = function(e) {
if(/\d/.test(this.value)) {
var sum = [].slice.call(inpt).reduce(function(a, b) {
if (a.value.length && b.value.length) {
return +a.value + +b.value;
} else {
return +a.value || +b.value;
}
})
out.value = sum || this.value;
} else {
out.value = "";
}
}
inpt.forEach(function(el) {
el.addEventListener('input', onInput, false)
})
<input class="attendance" type="text" name="attendance_1" value="" /> <span>+</span>
<input class="attendance" type="text" name="attendance_2" value="" />
<br><br>
<input id="attendance_output" type="text" value="" disabled />

Auto-changes between 2 inputs with controls

I have 2 inputs that only accepts positive floats with 2 decimals (other characters should be removed by change() function).
When the value of an input is changed, the value of the other input is automatically changed too.
Issue #1 - Main problem
My regex does not block beyond 2 decimals and allow severals . (eg: 12.345.67 sadly works).
Issue #2
Forbidden chars are not properly removed on the call of change(). I get
Error: $scope.uc.replace is not a function
This occurs because replace() only works on strings, and math operators (+, -, *, /) only works on numbers. I need to use both, how to deal with it?
Here is my code, you can use this JSFiddle if you want to try it yourself.
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.coeff = 0.5;
$scope.uf = '25';
$scope.uc = '';
$scope.change = function(type) {
console.log(type, "changes!");
$scope.uf = $scope.uf.replace(',', '.');
$scope.uf = $scope.uf.replace(/[^\d.-]/g, '');
$scope.uc = $scope.uc.replace(',', '.');
$scope.uc = $scope.uc.replace(/[^\d.-]/g, '');
if(type == 'uf') {
$scope.uc = $scope.uf * $scope.coeff;
} else if(type == 'uc') {
$scope.uf = $scope.uc / $scope.coeff;
}
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<input type="text" ng-model="uf" ng-change="change('uf')"/>
<input type="text" ng-model="uc" ng-change="change('uc')"/>
</div>
What about using input type="number" instead?
http://jsfiddle.net/Lvc0u55v/7192/
<div ng-controller="MyCtrl">
<input type="number" step="0.01" ng-model="uf" ng-change="change('uf')"/>
<input type="number" step="0.01" ng-model="uc" ng-change="change('uc')"/>
</div>
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.coeff = 0.5;
$scope.uf = "25";
$scope.uc = "";
$scope.change = function(type) {
console.log(type, "changes!");
if(type == 'uf') {
$scope.uc = $scope.uf * $scope.coeff;
} else if(type == 'uc') {
$scope.uf = $scope.uc / $scope.coeff;
}
}
}
For Issue #1, here is a regex that filter exactly what you want:
$scope.uf = $scope.uf.replace(',', '.')
.replace(/[^\d.]/g, '')
.replace(/\./, "x")
.replace(/\./g, "")
.replace(/x/, ".");
For Issue #2 I made the calculation in parseFloat:
$scope.uc = +parseFloat($scope.uf * $scope.coeff).toFixed(2);
$scope.uf = +parseFloat($scope.uf = $scope.uc / $scope.coeff).toFixed(2);
toFixed(2) allows only 2 decimals after ..
Finally, I put the code checking floats in a directive:
angular.module('myApp').directive('floatOnly', function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, element, attrs, modelCtrl) {
modelCtrl.$parsers.push(function(inputValue) {
if(inputValue === undefined) return '';
cleanInputValue = inputValue.replace(',', '.')
.replace(/[^\d.]/g, '')
.replace(/\./, "x")
.replace(/\./g, "")
.replace(/x/, ".");
if(cleanInputValue != inputValue) {
modelCtrl.$setViewValue(cleanInputValue);
modelCtrl.$render();
}
return cleanInputValue;
});
}
}
});
Used in HTML like this:
<div ng-controller="MyCtrl">
<input type="text" ng-model="uf" ng-change="change('uf')" float-only/>
<input type="text" ng-model="uc" ng-change="change('uc')" float-only/>
</div>
So change() function now looks like this:
$scope.change = function(type) {
console.log(type, "changes!");
if(type == 'uf') {
$scope.uc = +parseFloat($scope.uf * $scope.coeff).toFixed(2);
} else if(type == 'uc') {
$scope.uf = +parseFloat($scope.uf = $scope.uc / $scope.coeff).toFixed(2);
}
}
Working Fiddle

Password Validation with password bar & regExp special characters in angular using directive

This app is working for me BUT if someone find any error/mistake then please correct it.
I was create a small app for password validation using angular js directive. Where user can validate password that's required One Special & Capital character, and one num value with minimum length 8. i also created password strength bar with it.
Thanks
Here Plunkr Link my
Here is My HTML file :
<!DOCTYPE html>
<html>
<head>
<link data-require="bootstrap#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script data-require="jquery#*" data-semver="2.1.3" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script data-require="bootstrap#*" data-semver="3.3.1" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<script data-require="angular.js#*" data-semver="1.4.0-beta.3" src="https://code.angularjs.org/1.4.0-beta.3/angular.js"></script>
<script src="passwordModule.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div ng-app="passwordModule" ng-controller="pwdCtrl" class="container">
<h2>Password Validation:</h2>
<form name="form">
<div class="form-group">
<label>Password</label>
<input type="text" name="password" id="password" ng-model="user.password" ng-model-options="{allowInvalid: true}"
pattern-validator="((?=.*\d)(?=.*[A-Z])(?=.*\W).{8,8})" class="form-control"/>
</div>
<span class="alert alert-error" ng-show="form.password.$error.passwordPattern">
Password required 1 special & capital letter, 1 numeric letter <br> Required minimum 8 letter.</span>
<div class="form-group">
<label>Password Strength</label>
<password-strength ng-model="user.password"></password-strength>
<label>Confirm Password</label>
<input class="form-control" type = "text" name = "Confpassword" ng-model="user.cnfPwd" data-equal-to="password" >
<div data-ng-show = "showmsg"> Password matched </div>
<div data-ng-show = "hidemsg"> Password not matched </div>
</div>
<button class="btn btn-primary" type="button" ng-disabled = "disabledButton"> save </button>
</form>
</div>
<script type="text/javascript">
</script>
</body>
</html>
Here is My Controller File :
var pwdModule = angular.module('passwordModule', []);
//Controller
pwdModule.controller('pwdCtrl', ['$scope',
function($scope) {
// Initialise the password as hello
$scope.user = {};
$scope.showmsg = false;
$scope.disabledButton = true;
if($scope.user.password === undefined) {
$scope.showmsg = false;
}
$scope.$watch('user.cnfPwd', function(newVal, oldVal) {
if(newVal !== undefined){
$scope.hidemsg = true;
}
if(newVal === $scope.user.password && $scope.user.password !== undefined) {
$scope.showmsg = true;
$scope.disabledButton = false;
$scope.hidemsg = false;
} else {
$scope.showmsg = false;
$scope.disabledButton = true;
}
})
}
]);
// Directive: Validate a regex pattern
pwdModule.directive('patternValidator', [
function() {
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, elem, attrs, ctrl) {
ctrl.$parsers.unshift(function(viewValue) {
var patt = new RegExp(attrs.patternValidator);
var isValid = patt.test(viewValue);
ctrl.$setValidity('passwordPattern', isValid);
return viewValue;
});
}
};
}
]);
// Dircetive: Display strength bar
pwdModule.directive('passwordStrength', [
function() {
return {
require: 'ngModel',
restrict: 'E',
scope: {
password: '=ngModel'
},
link: function(scope, elem, attrs, ctrl) {
scope.$watch('password', function(newVal) {
var strength = isSatisfied(newVal && newVal.length >= 8) +
isSatisfied(newVal && /[A-z]/.test(newVal)) +
isSatisfied(newVal && /(?=.*\W)/.test(newVal)) +
isSatisfied(newVal && /\d/.test(newVal));
var style = '',
percent= 0;
switch (strength) {
case 1:
style = 'danger';
percent = 25;
break;
case 2:
style = 'warning';
percent = 50;
break;
case 3:
style = 'warning';
percent = 75;
break;
case 4:
style = 'success';
percent = 100;
break;
}
scope.style = style;
scope.percent = percent;
function isSatisfied(criteria) {
return criteria ? 1 : 0;
}
}, true);
},
template: '<div class="progress">' +
'<div class="progress-bar progress-bar-{{style}}" style="width: {{percent}}%"></div>' +
'</div>'
}
}
])
Please check this and if any modification needed then and on it. Thanks
Speaking about errors:
isSatisfied(newVal && /[A-z]/.test(newVal)) +
Here, [A-z] matches more than English letters, it also matches [, \, ], ^, _, and `, see this SO post.
In
isSatisfied(newVal && /(?=.*\W)/.test(newVal)) +
you should anchor the look-ahead to increase performance:
isSatisfied(newVal && /^(?=.*\W)/.test(newVal)) +
^
Note that {8,8} is equivalent to {8} - exactly 8 occurrences of the preceding subpattern. Use
pattern-validator="(?=.*\d)(?=.*[A-Z])(?=.*\W).{8}"
Or (if it is not anchored by default, can't find it anywhere):
pattern-validator="^(?=.*\d)(?=.*[A-Z])(?=.*\W).{8}$"

Categories