angular-input-types
Version:
AngularJS directives used on form inputs. Makes it easy for the users to input the correct information using autocomplete and validation.
141 lines (110 loc) • 5.13 kB
JavaScript
angular.module('inputTypes')
.provider('inputNumber', function() {
this.nrOfDecimals = 0;
this.$get = function() {
return this;
}
})
.directive('inputNumber', ['$browser', '$filter', '$locale', '$parse', '$sniffer', 'inputNumber', 'inputUtils', 'validate',
function($browser, $filter, $locale, $parse, $sniffer, inputNumber, inputUtils, validate) {
var thousandSeparator = $locale.NUMBER_FORMATS.GROUP_SEP;
var decimalSeparator = $locale.NUMBER_FORMATS.DECIMAL_SEP;
var nrOfDecimals = inputNumber.nrOfDecimals;
function plainNumber(value, decimals) {
if(value == null) {
return null;
}
var plainNumber = ('' + value).replace('.', decimalSeparator).replace(new RegExp('[^\\d\\-\\' + decimalSeparator + ']', 'g'), '');
var regExp = '^\\-?\\d+';
if(decimals > 0) {
regExp += '(\\' + decimalSeparator + '\\d{0,' + decimals + '})?';
}
plainNumber = plainNumber.match(new RegExp(regExp, 'g'));
return plainNumber === null ? null : plainNumber[0];
}
function setViewValue(inputElement, plainNumberValue, previousValueLength, scope) {
if(previousValueLength == plainNumberValue.length) {
return;
}
var cursorPosition = inputUtils.getCursorPos(inputElement[0]);
inputElement.val(plainNumberValue === null ? '' : format(plainNumberValue));
if(plainNumberValue === null) {
return 0;
}
var plainNumberLength = plainNumberValue.toString().split(decimalSeparator)[0].length;
if(plainNumberLength > 0 && plainNumberValue.charAt(0) == '-') {
// Remove the minus sign when calculating length for the thousand separators
plainNumberLength--;
}
if(inputElement[0] === document.activeElement) {
if(plainNumberLength > 1 && plainNumberLength % 3 == 1 && cursorPosition <= (plainNumberLength + Math.floor(plainNumberLength / 3))) {
// New thousand separator added
cursorPosition++;
}
if(cursorPosition > 1 && previousValueLength > plainNumberLength && previousValueLength % 3 > 0) {
// Character deleted and one less decimal separator
cursorPosition--;
}
scope.$evalAsync(inputUtils.setCursorPos(inputElement[0], cursorPosition));
}
return plainNumberLength;
}
function format(value) {
var parts = (value + '').split(decimalSeparator);
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandSeparator);
return parts.join(decimalSeparator);
}
function getNrOfDecimals(value, separator) {
return value.indexOf(separator) == -1 ? 0 : value.split(separator)[1].length;
}
function triggerInputEvent($sniffer, elm) {
if($sniffer.hasEvent('input')) {
elm.triggerHandler('input');
} else { // IE 11 Fix
elm.triggerHandler('change');
}
}
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
var attrDecimals = scope.$eval(attrs.decimals);
var previousValueLength = 0;
if(attrDecimals === undefined) {
attrDecimals = nrOfDecimals;
}
var attrMin = scope.$eval(attrs.min);
ctrl.$parsers.unshift(function(viewValue) {
if(viewValue == '') {
return null;
}
if(!viewValue) {
return undefined;
}
var modelValue = plainNumber(viewValue, attrDecimals);
if(modelValue == null || getNrOfDecimals(modelValue, decimalSeparator) > attrDecimals) {
return undefined;
}
previousValueLength = setViewValue(elm, modelValue, previousValueLength, scope);
if(getNrOfDecimals(viewValue, decimalSeparator) > attrDecimals ||
viewValue.lastIndexOf('-') <= 0 ||
viewValue.lastIndexOf('+') <= 0 ||
viewValue.lastIndexOf(' ') <= 0 ||
viewValue.replace('.', ',').indexOf(',') != viewValue.replace('.', ',').lastIndexOf(',')) {
triggerInputEvent($sniffer, elm);
}
ctrl.$validators.min = function(modelValue, viewValue) {
return ctrl.$isEmpty(modelValue) || attrMin === undefined || modelValue >= attrMin;
}
return modelValue === null ? null : modelValue.replace(decimalSeparator, '.').replace(/\.$/, '');
});
if (attrs.ngModel) {
var modelValue = $parse(attrs.ngModel)(scope);
if(modelValue) {
previousValueLength = setViewValue(elm, plainNumber(modelValue, attrDecimals), previousValueLength, scope);
triggerInputEvent($sniffer, elm);
}
}
}
}
}]);