I have pulled in some data for my app via an external JSON url which has resulted in the value I require, which is currently a string that is "0.00"
result.data.app_payamount = "0.00"
When I convert my strings into numbers and calculate a value I am only being returned a part number and not a full decimal value used for currency.
How can I edit this code so the payamount displays a full decimal number suitable for currency?
var deferred = $q.defer();
var results = response.data;
var urlStart = 'http://exmaple.com/api';
if (response.config.url.startsWith(urlStart)) {
angular.forEach(results, function(result, key) {
result.data.CardFee = 2.00;
result.data.app_bookingfee = result.data.CardFee;
result.data.app_payamount = +result.data.app_subtotal + +result.data.app_handling + -result.data.app_discount + +result.data.app_adjustment + +result.data.app_bookingfee;
});
In js, you can specify the number of digits like this:
n = n.toFixed(2);
Try to use Number.toFixed() here.
var deferred = $q.defer();
var results = response.data;
var urlStart = 'http://exmaple.com/api';
if (response.config.url.startsWith(urlStart)) {
angular.forEach(results, function(result, key) {
result.data.CardFee = 2.00;
result.data.app_bookingfee = result.data.CardFee;
result.data.app_payamount = +result.data.app_subtotal + +result.data.app_handling + -result.data.app_discount + +result.data.app_adjustment + +result.data.app_bookingfee;
result.data.app_payamount = result.data.app_payamount.toFixed(2);
});
Use number.toFixed(2):
var n = 2;
var nStringInteger = n.toFixed(0); // "2"
var nString1Decimal = n.toFixed(1); // "2.0"
var nString2Decimal = n.toFixed(2); // "2.00"
Use parseFloat and toFixed
<!DOCTYPE html>
<html>
<body>
<p>Click the button to parse different strings.</p>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<p id="demo2"></p>
<script>
function myFunction() {
var a = parseFloat("10.3265");
var b = parseFloat("10.00");
var c = parseFloat("10.33");
var n = a + b + c;
document.getElementById("demo").innerHTML = n;
document.getElementById("demo2").innerHTML = n.toFixed(2);
}
</script>
</body>
</html>
Use following currency directive to apply decimal places.
app.directive('currency', function ($filter, $locale) {
return {
require: 'ngModel',
scope: {
min: '=min',
max: '=max',
ngRequired: '=ngRequired'
},
link: function (scope, element, attrs, ngModel) {
function clearValue(value) {
value = String(value);
var dSeparator = $locale.NUMBER_FORMATS.DECIMAL_SEP;
var clear = value.match(/[\+\-0-9\.]/g);
clear = clear ? clear.join("") : 0;
return clear;
}
ngModel.$parsers.push(function (viewValue) {
cVal = clearValue(viewValue);
return parseFloat(cVal);
});
element.on("blur", function () {
if (isNaN(ngModel.$modelValue)) {
ngModel.$modelValue = 0;
element.val($filter('currency')(clearValue(ngModel.$modelValue)));
}
else {
element.val($filter('currency')(ngModel.$modelValue));
}
});
ngModel.$formatters.unshift(function (value) {
return $filter('currency')(value);
});
scope.$watch(function () {
return ngModel.$modelValue
}, function (newValue, oldValue) {
runValidations(newValue)
})
function runValidations(cVal) {
if (!scope.ngRequired && isNaN(cVal)) {
return
}
if (scope.min) {
var min = parseFloat(scope.min)
ngModel.$setValidity('min', cVal >= min)
}
if (scope.max) {
var max = parseFloat(scope.max)
ngModel.$setValidity('max', cVal <= max)
}
}
}
}
});
Related
I am tying to add thousand separator and decimal point to my text box.
I am using below directive also
.directive('format', function ($filter) {
'use strict';
return {
require: '?ngModel',
link: function (scope, elem, attrs, ctrl) {
if (!ctrl) {
return;
}
ctrl.$formatters.unshift(function () {
return $filter('number')(ctrl.$modelValue);
});
ctrl.$parsers.unshift(function (viewValue) {
var plainNumber = viewValue.replace(/[\,\.]/g, ''),
b = $filter('number')(plainNumber);
elem.val(b);
return plainNumber;
});
}
};
})
this is my Demo
i need to modify this.
When user enter 500,000, it should be like 500,000.00
and user can be enter 5000.50 also.
How i modify this, can u help
Take the decimal placement out of the users control.
num = 599993863737
num = str(num).replace('.','')
num = float(num[:len(num)-2]+'.'+num[-2:])
print(num)
5999938637.37
You can use toFixed() and regex
function currency(el){
a = parseFloat(el.value);
a = a.toFixed(2);
a=a.toString();
var b = a.replace(/[^\d\.]/g,'');
var dump = b.split('.');
var c = '';
var lengthchar = dump[0].length;
var j = 0;
for (var i = lengthchar; i > 0; i--) {
j = j + 1;
if (((j % 3) == 1) && (j != 1)) {
c = dump[0].substr(i-1,1) + ',' + c;
} else {
c = dump[0].substr(i-1,1) + c;
}
}
if(dump.length>1){
if(dump[1].length>0){
c += '.'+dump[1];
}else{
c += '.';
}
}
console.log(c);
}
<input type='text' onkeyup='currency(this)'>
I've done some searching around the web and nothing seems to solve my problem. I have the following jQuery code:
function youtube_data_parser(data) {
//---> parse video data - start
var qsToJson = function(qs) {
var res = {};
var pars = qs.split('&');
var kv, k, v;
for (i in pars) {
kv = pars[i].split('=');
k = kv[0];
v = kv[1];
res[k] = decodeURIComponent(v);
}
return res;
}
//---> parse video data - end
var get_video_info = qsToJson(data);
if (get_video_info.status == 'fail') {
return {
status: "error",
code: "invalid_url",
msg: "check your url or video id"
};
} else {
// remapping urls into an array of objects
//--->parse > url_encoded_fmt_stream_map > start
//will get the video urls
var tmp = get_video_info["url_encoded_fmt_stream_map"];
if (tmp) {
tmp = tmp.split(',');
for (i in tmp) {
tmp[i] = qsToJson(tmp[i]);
}
get_video_info["url_encoded_fmt_stream_map"] = tmp;
}
//--->parse > url_encoded_fmt_stream_map > end
//--->parse > player_response > start
var tmp1 = get_video_info["player_response"];
if (tmp1) {
get_video_info["player_response"] = JSON.parse(tmp1);
}
//--->parse > player_response > end
//--->parse > keywords > start
var keywords = get_video_info["keywords"];
if (keywords) {
key_words = keywords.replace(/\+/g, ' ').split(',');
for (i in key_words) {
keywords[i] = qsToJson(key_words[i]);
}
get_video_info["keywords"] = {
all: keywords.replace(/\+/g, ' '),
arr: key_words
};
}
//--->parse > keywords > end
//return data
return {
status: 'success',
raw_data: qsToJson(data),
video_info: get_video_info
};
}
}
function getVideoInfo() {
var get_video_url = $('#ytdlUrl').val();
var get_video_id = getUrlVars(get_video_url)['v'];
var video_arr_final = [];
var ajax_url = "video_info.php?id=" + get_video_id;
$.get(ajax_url, function(d1) {
var data = youtube_data_parser(d1);
var video_data = data.video_info;
var player_info = data.video_info.player_response;
var video_title = player_info.videoDetails.title.replace(/\+/g, ' ');
var fmt_list = video_data.fmt_list.split(',');
var video_thumbnail_url = video_data.thumbnail_url;
var video_arr = video_data.url_encoded_fmt_stream_map;
//create video file array
$.each(video_arr, function(i1, v1) {
var valueToPush = {};
valueToPush.video_url = v1.url;
valueToPush.video_thumbnail_url = video_thumbnail_url;
valueToPush.video_title = video_title;
$.each(fmt_list, function(i2, v2) {
var fmt = v2.split('/');
var fmt_id = fmt[0];
var fmt_quality = fmt[1];
if (fmt_id == v1.itag) {
valueToPush.fmt_id = fmt_id;
valueToPush.fmt_quality = fmt_quality;
}
});
video_arr_final.push(valueToPush);
});
});
return video_arr_final;
}
function getUrlVars(url) {
var vars = {};
var parts = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {
vars[key] = value;
});
return vars;
}
function fillInOptions(ytOptions) {
//console.log(ytOptions);
//alert(ytOptions[0]);
var ytFill = ytOptions;
console.log(ytFill);
//ytFill.forEach(function(i,v) {
var ytdlOptions = $('#ytdlOptions');
ytFill.forEach(function(i,v) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
return true;
}
function showYTDLLoader() {
$('#ytdlInput').fadeOut(1000, function() {
$('#ytdlLoader').fadeIn(500);
});
var options = getVideoInfo();
//console.log(options);
if (fillInOptions(options) == true) {
//do rest
}
}
function showYTDLOptions() {
return true;
}
function startDownload() {
showYTDLLoader();
}
function hideYTDLLoader() {
$('#ytdlLoader').fadeOut(500);
}
function animateCSS(element, animationName, callback) {
const node = $(element);
node.addClass(animationName);
function handleAnimationEnd() {
node.removeClass(animationName);
node.animationend = null;
if (typeof callback === 'function') callback();
}
node.animationend = handleAnimationEnd();
}
When my button is clicked, I call showYTDLLoader() which gets an array of objects from the YouTube API that looks like this:
[
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=22&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&ratebypass=yes&dur=917.768&lmt=1572418007364260&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5535432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRgIhAIp-4gyUTLoXFetbY0ha_YnR7DJqsp_MNjjIxqDdfPZJAiEA_WPd21jgX9broBcigf8rcSEVoJb2_NX7t3XZQqytsSM%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "22",
"fmt_quality": "1280x720"
},
{
"video_url": "https://r7---sn-uxanug5-cox6.googlevideo.com/videoplayback?expire=1572496003&ei=Iw66Xa24H8PL3LUPiN25mAs&ip=2001%3A8003%3A749b%3Aa01%3A5cd8%3Ac610%3A6402%3Ad0fe&id=o-ADsVnoOoBQ6-SWzYZU7gHES06s7xQptJG6hn9WcakITY&itag=18&source=youtube&requiressl=yes&mm=31%2C29&mn=sn-uxanug5-cox6%2Csn-ntqe6n7r&ms=au%2Crdu&mv=m&mvi=6&pl=39&initcwndbps=1655000&mime=video%2Fmp4&gir=yes&clen=44248820&ratebypass=yes&dur=917.768&lmt=1572416976690256&mt=1572474311&fvip=4&fexp=23842630&c=WEB&txp=5531432&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cmime%2Cgir%2Cclen%2Cratebypass%2Cdur%2Clmt&sig=ALgxI2wwRQIhANTZJlBHFWQWCnfK11yvLiPUV26c6NzvqIMKjDwmsByMAiBUSy0ZJMo4GdHSiRU4xBDDLxLtzwKZAqAKCiB-1aViDQ%3D%3D&lsparams=mm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=AHylml4wRAIgacvP3zjEq-rVEZFrX7a_hC6TR-Zab7Ii-Fbaupjs_PcCIHdZht4l4ioYL3ERz7WNiSbnOnhm5iYxEECaQXPP2hUp",
"video_title": "Arnold Schwarzenegger on Son-in-law Chris Pratt, Pranking Sylvester Stallone & Terminator’s Return",
"fmt_id": "18",
"fmt_quality": "640x360"
}
]
But when I try and loop through each entry with fillInOptions(), my loop is never completed because the length is apparently zero. However, when I dump the array using console.log() it tells me the length is 2, and displays the above. I need to be able to add each option to my dropdown.
Thankyou!
UPDATE: Added full code, sorry!
It looks like your .forEach() is the root of the problem. The parameters of a forEach are currentValue, index like this: array.forEach(function(currentValue, index) {}); but it looks like you're using them in the opposite way
Try rewriting that iteration to this:
ytFill.forEach(function(v, i) {
console.log(i);
ytdlOptions.append(new Option(v.fmt_quality, v.fmt_id));
});
Notice the difference in the order of v and i in the parameters.
I am trying to extract different parts of a polynomial string like variables, coefficients and powers from a string in javascript. So far I am able to extract these from a simple polynomial string e.g. "-13x^2+2-12x^4".
I want to extend this to extract from a relatively complex polynomial string. Something like "-13x^2y^3+2-12x^-4".
Here is the code that I have:
function extractPolynomial(polynomialStr) {
var arr = [];
polynomialStr = polynomialStr.match(/[+-]?\d+(x|y)(\^\d)*|[+-\s]\d+/g);
polynomialStr.forEach(function (match) {
var vals = match.split('^');
var coeff = parseInt(vals[0]);
var variable = vals[0].match(/[a-z]/gi) ? vals[0].match(/[a-z]/gi)[0] : "";
var power = 1;
if(vals.length > 1){
power = parseInt(vals[1]);
}
else {
if (variable === "") {
power = 0;
}
else {
power = 1;
}
}
arr.push({
coeff: coeff,
variable: variable,
power: power
})
});
return arr;
}
Here is the fiddle: https://jsfiddle.net/889ruq7a/
With a bit of research on regex I got what I wanted.
Here is the function to extract all the information from a polynomial:
function extractPolynomial(polynomialStr) {
var arr = [];
polynomialStr = polynomialStr.match(/[+-]?\d*(x|y)(\^\d)*((y|x)(\^\d)*)*|[+-\s]\d+/g);
polynomialStr.forEach(function (match) {
var variable = match.match(/([a-z]\^\d|[a-z])/gi) ? match.match(/([a-z]\^\d|[a-z])/gi).join("") : " ";
var coeff = parseFloat(match.split(variable)[0]);
var power = 1;
var variables = [];
if (variable != " ") {
var tempVars = variable.match(/([a-z]\^\d|[a-z])/gi);
for (var i = 0; i < tempVars.length; i++) {
var oneVariable = { variable: "", power: 0 };
oneVariable.variable = tempVars[i].match(/[a-z]/gi)[0];
var tempV = tempVars[i].split("^");
if (tempV.length > 1) {
oneVariable.power = parseFloat(tempV[1]);
}
else {
oneVariable.power = 1;
}
variables.push(oneVariable);
}
}
else {
variables.push({ variable: "", power: 0 });
}
arr.push({
coeff: coeff,
variables: variables
});
});
return arr;
};
Here is the fiddle for it: https://jsfiddle.net/khubaib/40hm80qu/5/
I have an array ($scope.names) that contains some simple objects which I am applying some functions to clean the value from diacritics. When I print with console this value it shows me ok. For example: 'La 45 km nord- vest de Bucureşti' it will be 'La 45 km nord- vest de Bucuresti'.
I am applying this method and for another variable ($scope.searchText) to make the searchable compatible. Again, it's fine.
The problem is that even I am standardizing that two variables value, the filter it doesn't work. If I try to search for 'Bucures' it wont show me the object that contains the clean word 'Bucures' (original word 'Bucureş')...
What I have doing wrong?
The full code is here: http://plnkr.co/edit/D5WfiOGd5I3QfcNVdOmr?p=preview
The angular script is that:
var app = angular.module('myApp', []);
app.controller('namesCtrl', function($scope, $filter) {
$scope.names = [
{
"adresa": "Str. Calafatului nr. 10",
"latitudine": "44.1",
"localitatea": "GALICEA MARE",
"longitudine": "23.3",
},
{
"adresa": "bd. Elisabeta nr. 1",
"latitudine": "44.170901",
"localitatea": "CONSTANŢA",
"longitudine": "28.663195",
},
{
"POTLOGI": "La 45 km nord- vest de Bucureşti",
"latitudine": "44.564319",
"localitatea": "POTLOGI",
"longitudine": "25.588091",
}
]
$scope.searchText = "";
$scope.searchCleanText = "";
$scope.myFilter = function (items) {
for (var i = 0; i < items.length; i++) {
var boolChk = false;
angular.forEach(items[i], function (value, key) {
var cleanValue = removeDiacritics(value).toLowerCase();
if (boolChk === false) {
boolChk = cleanValue.includes($scope.searchCleanText);
}
console.log(value + ' ' + cleanValue.includes($scope.searchCleanText) + '\tboolChk = ' + boolChk);
return boolChk;
});
}
}
$scope.$watch('searchText', function() {
$scope.searchCleanText = removeDiacritics($scope.searchText).toLowerCase();
$scope.showItems = $filter('filter')($scope.names, $scope.searchText, $scope.myFilter($scope.names));
console.log($scope.showItems);
});
});
I have made some changes to the filter code
`
$scope.myFilter = function (item) {
//for (var i = 0; i < items.length; i++) {
var boolChk = false;
angular.forEach(item, function (value, key) {
var cleanValue = removeDiacritics(value).toLowerCase();
if (boolChk === false) {
boolChk = cleanValue.includes($scope.searchCleanText);
}
console.log(value + ' ' + cleanValue.includes($scope.searchCleanText) + '\tboolChk = ' + boolChk);
return boolChk;
});
return boolChk;
//}
}
$scope.$watch('searchText', function() {
$scope.searchCleanText = removeDiacritics($scope.searchText).toLowerCase();
$scope.showItems = $filter('filter')($scope.names, $scope.searchText, function(actual,expected){return $scope.myFilter(actual);});
console.log($scope.showItems);
});
`
Check this Plunk
The answer it was using the 'function (actual, expected)' to return a boolean value:
$scope.functionFilter = function (actual, expected) {
if (typeof actual === 'object') {
var obj = actual;
//console.log(obj);
var boolChk = false;
angular.forEach(obj, function (value, key) {
var cleanValue = removeDiacritics(value).toLowerCase();
if (boolChk === false) {
boolChk = cleanValue.includes($scope.searchCleanText);
}
});
console.log(obj);
console.log(boolChk);
return boolChk;
}
}
Below is my use of noUiSlider, which I love because of it lacks jQuery. However, the slider's set function seems to be broken whenever I use a range that starts in the negatives. I am assuming it is an actual issue with noUiSlider, but would love to check that I did not make a mistake.
Codepen:
http://codepen.io/anon/pen/avpvVz
Dependency:
https://github.com/leongersen/noUiSlider
HTML:
<div class="slider" start="10" range="-50, 50" step="1"></div>
<br>
<br>
<br>
<div class="slider" start="0, 50" range="-100, 100" step="1"></div>
JS:
var sliders = document.getElementsByClassName('slider');
var countSliderUpdates = 0;
var countSliderUpdatesRan = 0;
function updateTextValue(maxLabel, minLabel) {
return function (values, handle) {
countSliderUpdatesRan = countSliderUpdatesRan + 1;
if (countSliderUpdatesRan > countSliderUpdates) {
maxLabel.parentNode.classList.remove("text--before");
};
if ( handle ) {
maxLabel.value = values[handle];
} else {
minLabel.value = values[handle];
}
}
}
function updateSliderValue(minLabel, maxLabel, slider) {
return function (values, handle) {
maxLabel.parentNode.classList.remove("text--before");
slider.noUiSlider.set([Number(maxLabel.value), Number(minLabel.value)]);
}
}
var styleSliders = function() {
var sliderLabels = [];
var sliderLabelsMin = [];
var sliderLabelsMax = [];
for (var i = 0; i < sliders.length; ++i) {
sliders[i].classList.add("text--before");
var start = sliders[i].getAttribute('start');
var range;
var step = undefined;
if(sliders[i].getAttribute('range')) {
range = JSON.parse('[' + sliders[i].getAttribute('range') + ']');
} else if(start.indexOf(',') > -1) {
range = JSON.parse("[" + start + "]");
} else {
range = [0, Number(start)];
};
console.log(range);
var connect = 'lower';
if (start.indexOf(',') > -1) {
start = JSON.parse("[" + start + "]");
connect = true;
}
if(sliders[i].getAttribute('step')) {
step = Number(sliders[i].getAttribute('step'));
};
noUiSlider.create(sliders[i], {
start: start,
connect: connect,
range: {
'min': range[0],
'max': range[1]
},
step: step,
format: {
to: function ( value ) {
return value;
},
from: function ( value ) {
return value;
}
}
});
if (start.constructor === Array) {
sliderLabelsMin[i] = document.createElement('input');
sliderLabelsMin[i].type = 'text';
if (sliders[i].classList.contains('slider--dark')) {
sliderLabelsMin[i].className = 'text--dark text--slider';
} else {
sliderLabelsMin[i].className = 'text--light text--slider';
}
sliderLabelsMin[i].title = 'Range Minimum';
sliderLabelsMin[i].placeholder = 'Range Minimum';
sliderLabelsMin[i].setAttribute('touched', false);
sliders[i].appendChild(sliderLabelsMin[i]);
sliderLabelsMax[i] = document.createElement('input');
sliderLabelsMax[i].type = 'text';
if (sliders[i].classList.contains('slider--dark')) {
sliderLabelsMax[i].className = 'text--dark text--right text--slider';
} else {
sliderLabelsMax[i].className = 'text--light text--right text--slider';
}
sliderLabelsMax[i].title = 'Range Maximum';
sliderLabelsMax[i].placeholder = 'Range Maximum';
sliderLabelsMax[i].setAttribute('touched', false);
sliders[i].appendChild(sliderLabelsMax[i]);
countSliderUpdates = countSliderUpdates + 2;
sliders[i].noUiSlider.on('update', updateTextValue(sliderLabelsMax[i], sliderLabelsMin[i]));
sliderLabelsMax[i].addEventListener('change', updateSliderValue(sliderLabelsMax[i], sliderLabelsMin[i], sliders[i]));
sliderLabelsMin[i].addEventListener('change', updateSliderValue(sliderLabelsMax[i], sliderLabelsMin[i], sliders[i]));
} else {
sliderLabels[i] = document.createElement('input');
sliderLabels[i].type = 'text';
if (sliders[i].classList.contains('slider--dark')) {
sliderLabels[i].className = 'text--dark text--slider';
} else {
sliderLabels[i].className = 'text--light text--slider';
}
sliderLabels[i].title = 'Range Amount Choice';
sliderLabels[i].placeholder = 'Range Amount Choice';
sliderLabels[i].setAttribute('touched', false);
sliders[i].appendChild(sliderLabels[i]);
countSliderUpdates = countSliderUpdates + 1;
sliders[i].noUiSlider.on('update', updateTextValue(sliderLabels[i], sliderLabels[i]));
sliderLabels[i].addEventListener('change', updateSliderValue(sliderLabels[i], sliderLabels[i], sliders[i]));
}
};
};
styleSliders();
I can confirm your code only works with non-negative slider values.
Though, if you remove the format part in your initialiser it will also work with negative numbers :)
format: {
to: function ( value ) {
return value;
},
from: function ( value ) {
return value;
}
}
Regards,
Frank
Alternatively, if you need the formatting, make sure the 'from' function returns a number. It is passed a string, but if you return a number, it works again with negative values. (The 'to' function is passed a number, but you can let that one return a (formatted) string.
Example:
var useFloat = false;
...
format: {
to: function (value) {
return useFloat ? value.toFixed(1) : value.toFixed(0);
},
from: function (value) {
return useFloat ? parseFloat(value) : parseInt(value);
}
}