I have a directive that does several things to a group of six single digit text input:
1 Capitalize the input if the user enters a lower case alphabet character
2. Reject any non alphabet character
3. Move back one input if user presses backspace, and delete the previous character if the user presses backspace twice.
Items 1 and 2 work, but item 3 doesn't work as expected. Right now, backspace goes to previous input AND deletes the input in one step.
Here is the UPDATED code. How do I get #3 working as described?
Here's a Fiddle (caps not working in the Fiddle but works locally for me).
<input class="code-char" type="text" maxlength="1" ng-model="code[0]" capitalize>
<input class="code-char" type="text" maxlength="1" ng-model="code[1]" capitalize>
<input class="code-char" type="text" maxlength="1" ng-model="code[2]" capitalize>
.directive('capitalize', function() {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var capitalize = function(inputValue) {
if (inputValue == undefined) inputValue = '';
var charString = inputValue.replace(/[^a-zA-Z]/g, ''); //to reject non-alphabet characters
var shouldDelete = false;
var shouldMoveBack = true;
element.bind('keyup', function(event) {
var key = event.keyCode;
if(key === 8) {
if(shouldDelete == true) {
shouldDelete = false;
element[0].value ='';
} else {
shouldDelete = true;
if(!scope.$first && shouldMoveBack == true) {
element[0].previousElementSibling.focus();
shouldMoveBack == false;
} else {
shouldMoveBack == true;
}
}
} else {
if(charString > '') element[0].nextElementSibling.focus();
}
});
var capitalized = charString.toUpperCase();
if (capitalized !== inputValue) {
modelCtrl.$setViewValue(capitalized);
modelCtrl.$render();
}
return capitalized;
}
modelCtrl.$parsers.push(capitalize);
capitalize(scope[attrs.ngModel]); // capitalize initial value
}
};
})
Instead of focusing on the previous sibling for the first case , You could prevent the default behaviour of backspace by doing event.preventDefault() and create a keypress event with keyCode of left arrow and trigger it manually for achieving the first case of #3 . For the second case , you could keep a counter to see if backspace is pressed for the second time and trigger the default behaviour. Check the below sample .
var count = 0;
var leftArrow = $.Event("keyup");
leftArrow.which = 37;//37 being the keycode of left arrow
element.bind('keyup', function (event) {
var key = event.keyCode;
// 37 , 8
if (key === 8) {// if it is backspace
count++;
if (count > 1) {
count = 0;
} else {
// prevent the default behaviour
event.preventDefault();
// create a left arrow keypress event
element.triggerHandler(leftArrow);
}
}
}
Related
I'm beginner in angularjs. I create a costume directive which validate IP address on keyperss event of textbox. It's work good but, I think there will be more efficient way implementation with use of regx or any other thing like parser or filter etc.
please help me improve this.
//Declare Main and sub modules
angular.module('CompanyApp', []);
//Initialize variables when DOM is ready
angular.module('CompanyApp').run(['$rootScope', function ($rootScope) { } ]);
(function () {
'use strict';
angular.module('CompanyApp').controller('TestCtrl', ['$scope', '$rootScope', TestCtrl]);
function TestCtrl($scope, $rootScope) {
$scope.ipAddress = '';
}
})()
angular.module('CompanyApp').directive("ipValidator", function () {
var directive = {};
directive.restrict = 'A'
directive.compile = function (element, attributes) {
var link = function (scope, element, attrs) {
element.bind("keypress", function (e) {
var key = e.key;
var code = e.keyCode;
var txt = element.val();
txt += key;
var len = txt.length;
var lastchar = txt.charAt(len-2);
var txtList = txt.split('.');
if ((len == 1 ||lastchar==='.')&& code == 46) {
e.preventDefault();
}
else if (!(code <= 57 && code >= 46) || len >= 16 || txtList.length > 4) {
e.preventDefault();
}
else {
txtList.forEach(function (value) {
var intValue = parseInt(value);
if (intValue > 255 || intValue < 0) {
e.preventDefault();
}
});
}
});
}
return link;
}
return directive;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.2/angular.min.js"></script>
<div name="divCompanyContainer" ng-app="CompanyApp" ng-controller="TestCtrl" ng-init="Init()">
<input type="text" ng-model="ipAddress" ip-validator placeholder="Ip address" /> <br />
</div>
First, lets talk about regular expression. Then, the algorithm we could use.
Regular expressions and IP
(Note: the IP regexps came from Regular-expressions.info - How to Find or Validate an IP Address.)
The whole regular expression for an IP address could be:
^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
You can see that the three first bytes are both checked by the same pattern below (surrounded by ^ and $):
^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.)$
The fourth byte is different:
^(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
Simple algorithm
(Note: I'm only considering the keypress event.)
Since the IP is validated incrementally, we could assume at each validation that a part is already correct.
The algorithm would be, for each key press:
Get an array of entered bytes separated by a dot .
If the array contains more than four items, the user entered an extra dot after a valid IP, input is rejected, return false
If the penultimate byte is an empty string, the user tried to enter a second dot, input is rejected, return false
If the last byte is an empty string, that's okay because the user just entered a dot, return true
The last byte is not empty, let's check it with the relevant regexp; if it matches its regexp then return true else return false.
Below a working snippet you could adapt.
var first3BytesRg = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$/;
var fourthByteRg = /^(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
document.getElementById("ip").onkeypress = preventInvalid;
function preventInvalid(e) {
return validateIP(e.target.value + String.fromCharCode(e.which));
}
function validateIP(ip) {
var splitted = ip.split(".");
var nb = splitted.length;
if (nb > 4) return false;
if (splitted[nb - 2] == "") return false;
if (splitted[nb - 1] == "") return true;
if (nb < 4) {
return first3BytesRg.test(splitted[nb - 1]);
}
return fourthByteRg.test(splitted[nb - 1]);
}
IP <input type="text" id="ip" />
I am trying to implement a mechanism where specific items on a screen are navigable using arrows keys.
At the moment, I am drawing a red box around items as they move and pressing enter activates them.
I have the following directive:
(credits here and here)
.directive("moveNext", function() {
return {
restrict: "A",
link: function($scope, element,attrs) {
element.bind("keyup", function(e) {
if (e.which == 37) {
console.log ("MOVE LEFT:" + JSON.stringify(element));
element[0].classList.remove('selected');
var partsId = attrs.id.match(/move-(\d+)/);
console.log ("CURRENT PARTS="+JSON.stringify(partsId));
var currentId = parseInt(partsId[1]);
console.log ("Looking for move-"+(currentId-1));
var nextElement = angular.element(document.querySelectorAll('#move-' + (currentId - 1)));
// var $nextElement = element.next().find('movehere');
if(nextElement.length) {
nextElement[0].classList.add('selected');
nextElement[0].focus();
// $nextElement[0].style.border='5px solid red';;
}
}
if (e.which == 39) {
console.log ("MOVE RIGHT:" + JSON.stringify(element));
element[0].classList.remove('selected');
var partsId = attrs.id.match(/move-(\d+)/);
var currentId = parseInt(partsId[1]);
console.log ("CURRENT PARTS="+JSON.stringify(partsId));
var currentId = parseInt(partsId[1]);
var nextElement = angular.element(document.querySelectorAll('#move-' + (currentId + 1)));
console.log ("Looking for move-"+(currentId+1));
// var $nextElement = element.next().find('movehere');
if(nextElement.length) {
nextElement[0].classList.add('selected');
nextElement[0].focus();
// $nextElement[0].style.border='5px solid red';;
}
}
if (e.which == 13) {
console.log ("ENTER:" + JSON.stringify(element));
// element.triggerHandler('click');
}
});
if (event) event.preventDefault();
}
}
})
And then in the template I have the following, for example:
<div>
<button move-next id="move-1" ng-click="d1()">Yes</button>
<button move-next id="move-3" ng-click="d1()">Yes</button>
<button ng-click="d1()">No</button>
<button move-next id="move-2" ng-click="d1()">Yes</button>
</div>
Yes <!-- PROBLEM -->
Yes <!-- NEVER COMES HERE -->
The nice part is I can now navigate to any "clickable" element depending on the ID order I set, which is my intention. The problem is that focus() only works on items that are focusable, so once "move-4" is highlighted by the directive, the focus() doesn't really work so I can never move "next" to "move-5"
thanks
Problem solved:
I removed the directive, and instead wrote a global keyUpHandler
Inside the keyup handler, I kept state on last selected item ID, so I could +- it irrespective of whether an item is focusable or not.
I can now navigate arbitrary items on any view with direction pad.
The problem however is that move-Ids must be unique across views or I need to find a way to do a query only on the active view. I need to figure out how to do that. currentView = document.querySelector('ion-view[nav-view="active"]'); doesn't work.
The code (needs cleanup, but seems to work)
window.addEventListener('keyup', keyUpHandler, true);
function keyUpHandler(evt){
$timeout (function() {
var currentView = document.querySelector('ion-view[nav-view="active"]');
var keyCode=evt.keyCode;
var el, nextel;
if (keyCode == 13 ) {
if ($rootScope.dpadId >0) {
el = angular.element(currentView.querySelector('#move-' +$rootScope.dpadId));
el.triggerHandler('click');
}
return;
}
if (keyCode == 37 || keyCode == 39) {
if ($rootScope.dpadId < 1) {
console.log ("First dpad usage");
$rootScope.dpadId = 1;
el = angular.element(currentView.querySelector('#move-1'));
if (el.length) {
el[0].classList.add('selected');
}
} else {
// unselect old
el = angular.element(currentView.querySelector('#move-' +$rootScope.dpadId));
var nextId = (keyCode == 37) ? $rootScope.dpadId -1: $rootScope.dpadId + 1;
nextel = angular.element(currentView.querySelector('#move-' +nextId));
if (nextel.length) {
el[0].classList.remove('selected');
nextel[0].classList.add('selected');
$rootScope.dpadId = nextId;
}
console.log ("dpadID="+$rootScope.dpadId);
}
}
});
}
I simply want to convert a string of numbers to a number which will be displayed using thousand separated commas.
var value = "123456";
I want to display "123,465" in a grid.
I have looked some documentation on this but everything is about displaying it in HTML.
I want to display this in a dynamic grid.
function numberRenderer (params) {
return new Number (params.value);
}
I want to format the number so that I can convert that into a string for display.
Use a filter ...
HTML usage
{{ number_expression | number : fractionSize}}
Js usage
$filter('number')(number, fractionSize)
I appreciated the answer from #jbrown, but I was also hoping to find some type of solution to add commas to an input field as the user enters numbers. I ended up finding this directive which proved to be exactly what I needed.
HTML
<input type="text" ng-model="someNumber" number-input />
JAVASCRIPT
myApp.directive('numberInput', function($filter) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(modelValue) {
return setDisplayNumber(modelValue, true);
});
// it's best to change the displayed text using elem.val() rather than
// ngModelCtrl.$setViewValue because the latter will re-trigger the parser
// and not necessarily in the correct order with the changed value last.
// see http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/
// for an explanation of how ngModelCtrl works.
ngModelCtrl.$parsers.push(function(viewValue) {
setDisplayNumber(viewValue);
return setModelNumber(viewValue);
});
// occasionally the parser chain doesn't run (when the user repeatedly
// types the same non-numeric character)
// for these cases, clean up again half a second later using "keyup"
// (the parser runs much sooner than keyup, so it's better UX to also do it within parser
// to give the feeling that the comma is added as they type)
elem.bind('keyup focus', function() {
setDisplayNumber(elem.val());
});
function setDisplayNumber(val, formatter) {
var valStr, displayValue;
if (typeof val === 'undefined') {
return 0;
}
valStr = val.toString();
displayValue = valStr.replace(/,/g, '').replace(/[A-Za-z]/g, '');
displayValue = parseFloat(displayValue);
displayValue = (!isNaN(displayValue)) ? displayValue.toString() : '';
// handle leading character -/0
if (valStr.length === 1 && valStr[0] === '-') {
displayValue = valStr[0];
} else if (valStr.length === 1 && valStr[0] === '0') {
displayValue = '';
} else {
displayValue = $filter('number')(displayValue);
}
// handle decimal
if (!attrs.integer) {
if (displayValue.indexOf('.') === -1) {
if (valStr.slice(-1) === '.') {
displayValue += '.';
} else if (valStr.slice(-2) === '.0') {
displayValue += '.0';
} else if (valStr.slice(-3) === '.00') {
displayValue += '.00';
}
} // handle last character 0 after decimal and another number
else {
if (valStr.slice(-1) === '0') {
displayValue += '0';
}
}
}
if (attrs.positive && displayValue[0] === '-') {
displayValue = displayValue.substring(1);
}
if (typeof formatter !== 'undefined') {
return (displayValue === '') ? 0 : displayValue;
} else {
elem.val((displayValue === '0') ? '' : displayValue);
}
}
function setModelNumber(val) {
var modelNum = val.toString().replace(/,/g, '').replace(/[A-Za-z]/g, '');
modelNum = parseFloat(modelNum);
modelNum = (!isNaN(modelNum)) ? modelNum : 0;
if (modelNum.toString().indexOf('.') !== -1) {
modelNum = Math.round((modelNum + 0.00001) * 100) / 100;
}
if (attrs.positive) {
modelNum = Math.abs(modelNum);
}
return modelNum;
}
}
};
});
AngularJS Directive was found from: AngularJS number input formatted view
https://jsfiddle.net/benlk/4dto9738/
Very appreciative of what Anguna posted. The only thing it was missing for me was handling the decimal places like currency. I wanted it to automatically add 2 decimal places to the displayed value. However, this should only occur on initial display and then again when leaving a field. I updated the code to handle that scenario.
var app = angular.module("myApp", []);
app.directive('currencyInput', function ($filter) {
return {
require: 'ngModel',
link: function (scope, elem, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function (modelValue) {
var displayValue = setDisplayNumber(modelValue, true);
displayValue = setDecimal(displayValue);
return displayValue;
});
// it's best to change the displayed text using elem.val() rather than
// ngModelCtrl.$setViewValue because the latter will re-trigger the parser
// and not necessarily in the correct order with the changed value last.
// see http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/
// for an explanation of how ngModelCtrl works.
ngModelCtrl.$parsers.push(function (viewValue) {
setDisplayNumber(viewValue);
return setModelNumber(viewValue);
});
// occasionally the parser chain doesn't run (when the user repeatedly
// types the same non-numeric character)
// for these cases, clean up again half a second later using "keyup"
// (the parser runs much sooner than keyup, so it's better UX to also do it within parser
// to give the feeling that the comma is added as they type)
elem.bind('keyup focus', function () {
setDisplayNumber(elem.val());
});
elem.bind('blur', function () {
// Add Decimal places if they do not exist
var valStr = elem.val().toString();
valStr = setDecimal(valStr);
elem.val(valStr);
});
function setDisplayNumber(val, formatter) {
var valStr, displayValue;
if (typeof val === 'undefined') {
return 0;
}
valStr = val.toString();
displayValue = valStr.replace(/,/g, '').replace(/[A-Za-z]/g, '');
displayValue = parseFloat(displayValue);
displayValue = (!isNaN(displayValue)) ? displayValue.toString() : '';
// handle leading character -/0
if (valStr.length === 1 && valStr[0] === '-') {
displayValue = valStr[0];
} else if (valStr.length === 1 && valStr[0] === '0') {
displayValue = '';
} else {
displayValue = $filter('number')(displayValue);
}
// handle decimal
if (!attrs.integer) {
if (displayValue.indexOf('.') === -1) {
if (valStr.slice(-1) === '.') {
displayValue += '.';
} else if (valStr.slice(-2) === '.0') {
displayValue += '.0';
} else if (valStr.slice(-3) === '.00') {
displayValue += '.00';
}
} // handle last character 0 after decimal and another number
else {
if (valStr.slice(-1) === '0') {
displayValue += '0';
}
}
}
if (attrs.positive && displayValue[0] === '-') {
displayValue = displayValue.substring(1);
}
if (typeof formatter !== 'undefined') {
return (displayValue === '') ? 0 : displayValue;
} else {
elem.val((displayValue === '0') ? '' : displayValue);
}
}
function setModelNumber(val) {
var modelNum = val.toString().replace(/,/g, '').replace(/[A-Za-z]/g, '');
modelNum = parseFloat(modelNum);
modelNum = (!isNaN(modelNum)) ? modelNum : 0;
if (modelNum.toString().indexOf('.') !== -1) {
modelNum = Math.round((modelNum + 0.00001) * 100) / 100;
}
if (attrs.positive) {
modelNum = Math.abs(modelNum);
}
return modelNum;
}
function setDecimal(val) {
// Add Decimal places if they do not exist
var valStr = val.toString();
// If no decimal then add it
if (valStr.indexOf('.') === -1) {
valStr += '.00';
}
else {
var decimalDigits = valStr.length - (valStr.indexOf('.') + 1);
var missingZeros = 2 - decimalDigits;
for (var i = 1; i <= missingZeros; i++) {
valStr += '0';
}
}
return valStr;
}
}
};
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js"></script>
<div ng-app="myApp">
<input type="text" ng-model="myModelValue" currency-input />
</div>
I am creating a directive to validate the age of a user and I am using it in combination with ui-mask. The html for my input is as such:
<input id="dateOfBirth" name="dateOfBirth" type="text" class="form-control" ng-model="owner.dateOfBirth" placeholder="mm/dd/yyyy" required ui-mask="99/99/9999" minimum-age="18">
and the directive (copied from the blacklist directive example here on stackoverflow):
angular.module('Pensco.AEW.Directives')
.directive('minimumAge', function (){
return {
require: 'ngModel',
link: function(scope, elem, attr, ngModel) {
var minimumAge = parseInt(attr.minimumAge, 10),
minDate = new Date(),
monthsToSubtract = 12 * minimumAge;
// subtract the months from today
minDate.setMonth(minDate.getMonth() - monthsToSubtract);
//For DOM -> model validation
ngModel.$parsers.unshift(function(value) {
var valid = isValid(value);
ngModel.$setValidity('minimumAge', valid);
return value;
});
//For model -> DOM validation
ngModel.$formatters.unshift(function(value) {
var valid = isValid(value);
ngModel.$setValidity('minimumAge', valid);
return value;
});
function cleanMask(value) {
var parts;
if (!value) { return; }
parts = value.split('/');
parts[0] = checkLength(parts[0], 2, 'm');
parts[1] = checkLength(parts[1], 2, 'd');
parts[2] = checkLength(parts[2], 4, 'y');
return parts.join('/');
}
function checkLength(value, len, character) {
if (value.length > len) {
value = value.slice(0, - 1);
} else if (value.length < len) {
value = value + character;
}
return value;
}
function isValid(value) {
var cleanedValue = cleanMask(value),
dob = new Date(cleanedValue);
// if the date is valid then compare it to calculated min date
if (isDate(dob)) {
return dob <= minDate;
}
return false;
}
function isDate(value) {
return value instanceof Date && isFinite(value)
}
}
};
});
The issue is that value is that when the user types a number such as 0, value is set to "0mm/dd/yyyy" as it appears that ui-mask has not removed the placeholder character yet to make it "0m/dd/yyyy". ui-mask has its priority set to 100, so I set the priority of this directive to -1000 thinking it might have the mask finish processing before processing my directive. After my directive is completed it appears that ui-mask finishes processing and removes the placeholder character.
I added a couple of methods to clean and validate the dates, which works, and yet, I have to believe there is a cleaner way to handle it. Any ideas on how I can my directive to fire after ui-mask is done processing?
I found a issue in your code.In checklength methos throw TypeError: Cannot read property 'length' of undefined
I have change the code to
function checkLength(value, len, character) {
if(value!=undefined)
{
if (value.length > len) {
value = value.slice(0, - 1);
} else if (value.length < len) {
value = value + character;
}
}
return value;
}
Check this Working Sample which is working correctly.
I want to use a formatted number input to show thousand seperator dots to user when he types big numbers. Here is the directive code that I used: http://jsfiddle.net/LCZfd/3/
When I use input type="text" it works, but when I want to use input type="number" it's weirdly cleaning by something when user typing big numbers.
What is problem about input[number]?
As written in the comments, input type="number" doesn't support anything but digits, a decimal separator (usually , or . depending on the locale) and - or e. You may still enter whatever you want, but the browser will discard any unknown / incorrect character.
This leaves you with 2 options:
Use type="text" and pattern validation like pattern="[0-9]+([\.,][0-9]+)*" to limit what the user may enter while automatically formatting the value as you do in your example.
Put an overlay on top of the input field that renders the numbers how you want and still allows the user to use the custom type="number" input controls, like demonstrated here.
The latter solution uses an additional <label> tag that contains the current value and is hidden via CSS when you focus the input field.
All these years later, there still isn't an HTML5 solution out of the box for this.
I am using <input type="tel"> or <input type="text"> ("tel" brings up a numeric keyboard in Android and iOS, which in some cases is a bonus.)
Then I needed a directive to:
filter out non-numeric characters
add thousand-separator commas as the user types
use $parsers and keyup to set elem.val() and $formatters to set the display...
...while behind the scenes, assign ng-model a floating point number
The directive example below does this, and it accepts negatives and floating point numbers unless you specify you want only positive or integers.
It's not the full solution I would like, but I think it bridges the gap.
HTML
<input type="text" ng-model="someNumber" number-input />
JAVASCRIPT
myApp.directive('numberInput', function($filter) {
return {
require: 'ngModel',
link: function(scope, elem, attrs, ngModelCtrl) {
ngModelCtrl.$formatters.push(function(modelValue) {
return setDisplayNumber(modelValue, true);
});
// it's best to change the displayed text using elem.val() rather than
// ngModelCtrl.$setViewValue because the latter will re-trigger the parser
// and not necessarily in the correct order with the changed value last.
// see http://radify.io/blog/understanding-ngmodelcontroller-by-example-part-1/
// for an explanation of how ngModelCtrl works.
ngModelCtrl.$parsers.push(function(viewValue) {
setDisplayNumber(viewValue);
return setModelNumber(viewValue);
});
// occasionally the parser chain doesn't run (when the user repeatedly
// types the same non-numeric character)
// for these cases, clean up again half a second later using "keyup"
// (the parser runs much sooner than keyup, so it's better UX to also do it within parser
// to give the feeling that the comma is added as they type)
elem.bind('keyup focus', function() {
setDisplayNumber(elem.val());
});
function setDisplayNumber(val, formatter) {
var valStr, displayValue;
if (typeof val === 'undefined') {
return 0;
}
valStr = val.toString();
displayValue = valStr.replace(/,/g, '').replace(/[A-Za-z]/g, '');
displayValue = parseFloat(displayValue);
displayValue = (!isNaN(displayValue)) ? displayValue.toString() : '';
// handle leading character -/0
if (valStr.length === 1 && valStr[0] === '-') {
displayValue = valStr[0];
} else if (valStr.length === 1 && valStr[0] === '0') {
displayValue = '';
} else {
displayValue = $filter('number')(displayValue);
}
// handle decimal
if (!attrs.integer) {
if (displayValue.indexOf('.') === -1) {
if (valStr.slice(-1) === '.') {
displayValue += '.';
} else if (valStr.slice(-2) === '.0') {
displayValue += '.0';
} else if (valStr.slice(-3) === '.00') {
displayValue += '.00';
}
} // handle last character 0 after decimal and another number
else {
if (valStr.slice(-1) === '0') {
displayValue += '0';
}
}
}
if (attrs.positive && displayValue[0] === '-') {
displayValue = displayValue.substring(1);
}
if (typeof formatter !== 'undefined') {
return (displayValue === '') ? 0 : displayValue;
} else {
elem.val((displayValue === '0') ? '' : displayValue);
}
}
function setModelNumber(val) {
var modelNum = val.toString().replace(/,/g, '').replace(/[A-Za-z]/g, '');
modelNum = parseFloat(modelNum);
modelNum = (!isNaN(modelNum)) ? modelNum : 0;
if (modelNum.toString().indexOf('.') !== -1) {
modelNum = Math.round((modelNum + 0.00001) * 100) / 100;
}
if (attrs.positive) {
modelNum = Math.abs(modelNum);
}
return modelNum;
}
}
};
});
https://jsfiddle.net/benlk/4dto9738/
You need to add the step attribute to your number input.
<input type="number" step="0.01" />
This will allow floating points.
http://jsfiddle.net/LCZfd/1/
Also, I'd recommend reviewing the bug thread on number inputs in Firefox. You may want to consider not using this input type, as it was just finally supported in this release of FF.
https://bugzilla.mozilla.org/show_bug.cgi?id=344616
http://caniuse.com/input-number
You cannot use values with , because type=number only takes numbers, adding a comma makes it a string.
See http://jsfiddle.net/LCZfd/5
You're better off making your own controls if you want commas. One with a true value (the number) and a display value (the string).
you can try this, I modified the directive I saw here...
How do I restrict an input to only accept numbers? ...
here's the modified directive I made... This directive uses the keyup event to modify the input on the fly...
.directive('numericOnly', function($filter) {
return {
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
element.bind('keyup', function (inputValue, e) {
var strinput = modelCtrl.$$rawModelValue;
//filter user input
var transformedInput = strinput ? strinput.replace(/[^,\d.-]/g,'') : null;
//remove trailing 0
if(transformedInput.charAt(0) <= '0'){
transformedInput = null;
modelCtrl.$setViewValue(transformedInput);
modelCtrl.$render();
}else{
var decimalSplit = transformedInput.split(".")
var intPart = decimalSplit[0];
var decPart = decimalSplit[1];
//remove previously formated number
intPart = intPart.replace(/,/g, "");
//split whole number into array of 3 digits
if(intPart.length > 3){
var intDiv = Math.floor(intPart.length / 3);
var strfraction = [];
var i = intDiv,
j = 3;
while(intDiv > 0){
strfraction[intDiv] = intPart.slice(intPart.length-j,intPart.length - (j - 3));
j=j+3;
intDiv--;
}
var k = j-3;
if((intPart.length-k) > 0){
strfraction[0] = intPart.slice(0,intPart.length-k);
}
}
//join arrays
if(strfraction == undefined){ return;}
var currencyformat = strfraction.join(',');
//check for leading comma
if(currencyformat.charAt(0)==','){
currencyformat = currencyformat.slice(1);
}
if(decPart == undefined){
modelCtrl.$setViewValue(currencyformat);
modelCtrl.$render();
return;
}else{
currencyformat = currencyformat + "." + decPart.slice(0,2);
modelCtrl.$setViewValue(currencyformat);
modelCtrl.$render();
}
}
});
}
};
you use it like this ...
<input type="text" ng-model="amountallocated" id="amountallocated" numeric-only />