whole number pad with zeros - javascript

I have a directive that convert to 2 decimal places (input number textbox) and
it is working well but I would like to pad the whole number with zeros.
Anyone knows how I can achieve whole number with padded zeros? Example below.
2 -> 2.00 - not done
10.666 -> 10.67 - done
app.directive('toPrecision',['$filter', function ($filter) {
return {
replace: false,
restrict: 'A',
link: function(scope, element, attr) {
var input = angular.element(element);
var precisionValue = attr.toPrecision;
input.on('keyup', function() {
var parsed = parseFloat(input.val());
if (!isNaN(parsed)) {
if (parseInt(parsed, 10) !== parsed && String(parsed).split('.')[1].length > 2) {
var result = parsed.toFixed(precisionValue);
input.val(result);
}
}
});
}
}
}]);
HTML
<input type="number" class="form-control" ng-model="rate" to-precision="2" min="0" step="1">

Ended rewriting the directives for what I want.
app.directive('toPrecision', function() {
return {
replace: false,
restrict: 'EA',
require: 'ngModel',
link: function(scope, element, attr, ngModelCtrl) {
var input = angular.element(element);
var precisionValue = attr.toPrecision;
ngModelCtrl.$parsers.push(function(value) {
var clean = value.replace(/[^-0-9\.]/g, '');
if (value !== clean) {
ngModelCtrl.$setViewValue(clean);
ngModelCtrl.$render();
}
return clean;
});
ngModelCtrl.$formatters.push(function(value) {
if (angular.isUndefined(value)) {
return "";
}
var parsed = parseFloat(value);
return parsed.toFixed(precisionValue);
});
input.on('blur', function() {
var parsed = parseFloat(input.val());
if (!isNaN(parsed)) {
var result = parsed.toFixed(precisionValue);
input.val(result);
ngModelCtrl.$setViewValue(result);
}
});
}
}});

Here's code to do it taken from the answer I voted to close as duplicate:
var s = number.toString();
if (s.indexOf('.') == -1) s += '.';
while (s.length < s.indexOf('.') + 4) s += '0';

Let math do it, Try this.
if (!isNaN(parsed)) {
parsed += Math.pow(10, -1 * (precisionValue + 2)); // 2 + 0.0001
var result = parsed.toFixed(precisionValue); // 2.00
input.val(result);
}
See fiddle

Related

How can I remove currency in an Angularjs directive?

I'm using the directive for displaying money in proper format from this url http://jsfiddle.net/ExpertSystem/xKrYp/
Does anyone know how can I remove the $ symbol from the output value and have only the actual amount converted?
Tried few different things but I was not able to accomplish what I was looking for.
Here is the directive as well:
app.directive('realTimeCurrency', function ($filter, $locale) {
var decimalSep = $locale.NUMBER_FORMATS.DECIMAL_SEP;
var toNumberRegex = new RegExp('[^0-9\\' + decimalSep + ']', 'g');
var trailingZerosRegex = new RegExp('\\' + decimalSep + '0+$');
var filterFunc = function (value) {
return $filter('currency')(value);
};
function getCaretPosition(input){
if (!input) return 0;
if (input.selectionStart !== undefined) {
return input.selectionStart;
} else if (document.selection) {
// Curse you IE
input.focus();
var selection = document.selection.createRange();
selection.moveStart('character', input.value ? -input.value.length : 0);
return selection.text.length;
}
return 0;
}
function setCaretPosition(input, pos){
if (!input) return 0;
if (input.offsetWidth === 0 || input.offsetHeight === 0) {
return; // Input's hidden
}
if (input.setSelectionRange) {
input.focus();
input.setSelectionRange(pos, pos);
}
else if (input.createTextRange) {
// Curse you IE
var range = input.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
function toNumber(currencyStr) {
return parseFloat(currencyStr.replace(toNumberRegex, ''), 10);
}
return {
restrict: 'A',
require: 'ngModel',
link: function postLink(scope, elem, attrs, modelCtrl) {
modelCtrl.$formatters.push(filterFunc);
modelCtrl.$parsers.push(function (newViewValue) {
var oldModelValue = modelCtrl.$modelValue;
var newModelValue = toNumber(newViewValue);
modelCtrl.$viewValue = filterFunc(newModelValue);
var pos = getCaretPosition(elem[0]);
elem.val(modelCtrl.$viewValue);
var newPos = pos + modelCtrl.$viewValue.length -
newViewValue.length;
if ((oldModelValue === undefined) || isNaN(oldModelValue)) {
newPos -= 3;
}
setCaretPosition(elem[0], newPos);
return newModelValue;
});
}
};
});
Try https://github.com/bcherny/format-as-currency :)
Or if you want to use your own version, pass an empty string as a 2nd argument to the currency filter. See https://docs.angularjs.org/api/ng/filter/currency

Angular directive for multiple elements

I created this number format directive, but if I use it on more than one input, it doesn't work for all of them, but with only one it works.
Any ideas?
directive('formatUsNumber', function() {
return {
restrict: 'A',
require: 'ngModel',
priority: 100,
link: function(scope, element, attrs, ngModel) {
scope.formatNumber = function() {
var n = element.val();
var dest = n;
if (n.length >= 10) {
if (/^[A-Za-z\s]+$/.test(n)) {
return;
}
dest = n.replace(/\D/g, '');
if (!isNaN(dest)) {
n = dest;
}
if (n.substr(0, 1) != "1") {
n = "1" + n;
}
}
element.val(n);
ngModel.$setViewValue(n);
};
},
};
});
The template:
<input type="text" ng-change="formatNumber()" format-us-number ng-model="myModel" />
Fiddle: http://jsfiddle.net/Lvc0u55v/7479/
I think it's because scope of directive is not isolated.
And also I've made few changes, hope it workes the same
directive('formatUsNumber', function() {
return {
restrict: 'A',
require: 'ngModel',
priority: 100,
scope: true,
link: function(scope, element, attrs, ngModel) {
scope.formatNumber = function() {
var n = ngModel.$modelValue;
if (n.length >= 10) {
if (/^[A-Za-z\s]+$/.test(n)) {
return;
}
n = n.replace(/\D/g, '');
if (!isNaN(dest)) {
n = dest;
}
if (n.substr(0, 1) != "1") {
n = "1" + n;
}
ngModel.$setViewValue(n, 'change:directive');
}
};
},
};
});
U can test it here
Try adding an isolated scope, something like this:
restrict: 'A',
require: 'ngModel',
priority: 100,
scope:{
ngModel:'='
},...
For this use case I think that fits better implements a custom filter instead a directive.
Building Custom AngularJS Filters
Other alternative could be incude a custom parser and/or formatter.
AngularJS - Formatters and Parsers

Trying to underline the first occurence of a character with Javascript/Angular

I have some anchor tags where I'm using an angular directive to decorate (underline) the text(to indicate a keyboard shortcut). So far my code only works if the specified character (for "amt-alt-key") is at the beginning of the first word.
What I need to do is search the whole string and underline the first occurrence of the specified character. So right now if I specified an amt-alt-key="A" in the example below it would work fine as is. However, the problem is the first occurrence could be anywhere in the anchor text. Any help with writing the correct JavaScript would be greatly appreciated.
--Jason
In my html
Agent Data
In my angular code
app.directive("amtAltKey", function () {
return {
link: function (scope, elem, attrs) {
var altKey = attrs.amtAltKey.toUpperCase();
var text = el.innerText;
var textUpper = text.toUpperCase();
var indexOfKey = textUpper.indexOf(altKey);
var newText = text.substring(0, indexOfKey);
newText += '<u>' + text.substring(indexOfKey, 1) + '</u>';
if (indexOfKey + 1 < text.length) { newText += text.substring(indexOfKey + 1); }
el.innerHTML = newText;
keyListeners[altKey] = el;
}
};
});
You can use Regular expression to check the required pattern and a replaceText utility function to replace the matched pattern and once you have the text, replace the existing content of the element as below:
.directive('amtAltKey', function () {
return {
link: function (scope, elem, attrs) {
var altKey = new RegExp(attrs.amtAltKey, 'i');
var text = elem.text();
function replaceText (txt) {
function underline(match) {
return '<u>' + match +'</u>';
}
return txt.replace(altKey, underline);
}
var newText = replaceText(text);
elem.html(newText);
}
};
});
Here is a working example: https://jsbin.com/zefodo/2/edit?html,js,console,output
Use this:
app.directive("amtAltKey", function () {
return {
link: function (scope, elem, attrs) {
var altKey = attrs.amtAltKey;
var text = elem.innerText;
elem.innerHTML = text.replace(new RegExp(altKey, 'i'), '<u>$&</u>');
keyListeners[altKey] = elem;
}
};
});
Try this
app.directive("amtAltKey", function() {
return {
link: function(scope, elem, attrs) {
var el = elem[0];
var altKey = "" + attrs.amtAltKey.toUpperCase();
var text = el.innerText;
var textUpper = text.toUpperCase();
var indexOfKey = textUpper.indexOf(altKey);
if (indexOfKey > -1) {
var newText = text.substr(0, indexOfKey);
newText += '<u>' + text.substr(indexOfKey, 1) + '</u>';
if (indexOfKey + 1 < text.length) {
newText += text.substr(indexOfKey + 1);
}
el.innerHTML = newText;
keyListeners[altKey] = el;
}
}
};
});

Disable that acceess key sets focus to button

I have created a access key Angular directive.
angular.module('tcne.common').directive("accessKey", function () {
return {
restrict: "A",
scope: {
},
link: function (scope, element, attrs) {
var $element = $(element);
$element.attr("accesskey", attrs.accessKey);
var content = $element.html();
for (var i = 0; i < content.length; i++) {
var char = content[i];
if (char.toLowerCase() === attrs.accessKey.toLowerCase()) {
content = content.substr(0, i) + "<u>" + char + "</u>" + content.substr(i + 1);
break;
}
}
$element.html(content);
},
replace: false
};
});
It underscores the access key in the button Label and adds the access key attribute to the element. Can I somehow prevent the accesskey from setting the button in focus? It kills the purpose of keyboard short cuts
edit: Rolled my own acccess key
angular.module('tcne.common').directive('accessKey', ['$compile', '$interval', function ($compile, $interval) {
var modifierPressed = false;
$("body").keyup(function (e) {
if (modifierPressed && !e.altKey) {
modifierPressed = false;
digestScopes();
}
});
$("body").keydown(function (e) {
modifierPressed = e.altKey;
if (modifierPressed && scopes.hasOwnProperty(String.fromCharCode(e.which).toLowerCase())) {
var scope = scopes[String.fromCharCode(e.which).toLowerCase()];
scope.handle();
return;
}
if (modifierPressed) {
e.preventDefault();
digestScopes();
}
});
function digestScopes() {
for (var index in scopes) {
if (scopes.hasOwnProperty(index)) {
var scope = scopes[index]
scope.$digest();
}
}
}
function isModifierPressed() {
return modifierPressed;
}
var scopes = {};
return {
restrict: 'A',
scope: {
},
link: function (scope, element, attrs) {
var key = attrs.accessKey.toLowerCase();
var content = element.html();
var char;
for (var i = 0; i < content.length; i++) {
char = content[i];
if (char.toLowerCase() === key) {
content = content.substr(0, i) + '<u><strong ng-if="highlight()">{{char}}</strong><span ng-if="!highlight()">{{char}}</span></u>' + content.substr(i + 1);
break;
}
}
element.html(content);
var underscoreScope = scope.$new();
underscoreScope.char = char;
underscoreScope.highlight = isModifierPressed;
underscoreScope.handle = element.click.bind(element);
scopes[key] = underscoreScope;
scope.$on('$destroy', function () {
delete scopes[key];
});
$compile(element.find("u"))(underscoreScope);
},
replace: false
};
}]);
It also highlights the access key button when alt key is pressed which is nice
Any pit falls with this code? Thanks
Found a pitfall, element.html and then $compile will break any directives inside the element that is already compiled. So I changed to
var captionElement = element.contents().first(":text");
var content = captionElement.text();
And then I add my custom content like
var view = $("<span>").html(content);
captionElement.replaceWith(view);
$compile(view)(vm);
Please let me know if this is considered bad practice

Angular directive for percentage input and validation (initial validation doesn't work)

I wrote an Angular directive to capture percentage values in fractions (100% = 1.0) in model, but whole numbers in view. It works great in most of the scenarios, but I am not sure how to trigger the initial validation.
For example, when the user is presented with the form, the default value is zero. When the min and max are set to 1 and 100, the validation doesn't happen.
Can someone let me know how to make it work in an elegant way?
Plunker link: http://plnkr.co/edit/ioraHEK63SuGMncTuHBw?p=info
export function PercentageInputFormatter() {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, vm) {
if (vm) {
var minNumber: number = 'min' in attrs ? parseFloat(attrs.min) : Number.MIN_VALUE;
var maxNumber: number= 'max' in attrs ? parseFloat(attrs.max) : Number.MAX_VALUE;
var allowFraction: boolean = 'fraction' in attrs ? attrs.fraction === 'true' : false;
vm.$parsers.push(function (value) {
return validatePercentage(value);
});
vm.$formatters.push(function (value) {
return XpressConvertionUtils.toPercentageDisplay(value, allowFraction ? 2 : 0);
});
function validatePercentage(value) {
if (value) {
var valid = !isNaN(parseFloat(value)) && isFinite(value) && parseFloat(value) >= minNumber && parseFloat(value) <= maxNumber;
if (!allowFraction)
valid = valid && value.indexOf('.') == -1;
vm.$setValidity('percentage', valid);
}
return valid ? value / 100 : undefined;
}
}
}
};
}
myApp.directive('dpInputFormatterPercentage', PercentageInputFormatter);
Found a solution, but please feel free to suggest better ways, as I feel this is a work-around and doesn't look very elegant. If not, hope this helps someone else.
This part did the trick:
var modelGetter = $parse(attrs.ngModel);
var initialValue = modelGetter(scope);
validatePercentage($filter('percentage')(initialValue, allowFraction ? 2 : 0));
Full directive code below:
export function PercentageInputFormatter($parse, $filter) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, element, attrs, vm) {
if (vm) {
var minNumber: number = 'min' in attrs ? parseFloat(attrs.min) : Number.MIN_VALUE;
var maxNumber: number= 'max' in attrs ? parseFloat(attrs.max) : Number.MAX_VALUE;
var allowFraction: boolean = 'fraction' in attrs ? attrs.fraction === 'true' : false;
var modelGetter = $parse(attrs.ngModel);
var initialValue = modelGetter(scope);
validatePercentage($filter('percentage')(initialValue, allowFraction ? 2 : 0));
vm.$parsers.push(function (value) {
return validatePercentage(value);
});
vm.$formatters.push(function (value) {
return $filter('percentage')(value, allowFraction ? 2 : 0);
});
function validatePercentage(value) {
if (value) {
var valid = !isNaN(parseFloat(value)) && isFinite(value) && parseFloat(value) >= minNumber && parseFloat(value) <= maxNumber;
if (!allowFraction)
valid = valid && value.indexOf('.') == -1;
vm.$setValidity('percentage', valid);
}
return valid ? value / 100 : undefined;
}
}
}
};
}

Categories