I'm still quite new to javascript and was wondering if there's a more efficient way to handle this situation, for example by using an array?
I have an HTML form with 6 fields that let you enter the last six weeks amount of overtime paid. I'm then using javascript to add the six values up, divide by six and multiply by 52 to obtain an annual overtime amount. My fields are named w_ot_1, w_ot_2 up to w_ot_6 and I'm using the code below. It all works fine but I'm finding it's really repetitive and it's not just overtime I need to run this calculation on. I'm sure there's got to be a more efficient way. Does anyone have any ideas that could help?
var weekly_ot_1 = parseFloat(document.getElementById("w_ot_1").value.replace(/[^0-9.]/g, ''));
var weekly_ot_2 = parseFloat(document.getElementById("w_ot_2").value.replace(/[^0-9.]/g, ''));
var weekly_ot_3 = parseFloat(document.getElementById("w_ot_3").value.replace(/[^0-9.]/g, ''));
var weekly_ot_4 = parseFloat(document.getElementById("w_ot_4").value.replace(/[^0-9.]/g, ''));
var weekly_ot_5 = parseFloat(document.getElementById("w_ot_5").value.replace(/[^0-9.]/g, ''));
var weekly_ot_6 = parseFloat(document.getElementById("w_ot_6").value.replace(/[^0-9.]/g, ''));
//weekly annualised overtime values
document.getElementById("w_annual_ot").value= addCommas((((weekly_ot_1 + weekly_ot_2 + weekly_ot_3 + weekly_ot_4 + weekly_ot_5 + weekly_ot_6)/6) * 52).toFixed(2));
This is a situation where you can leverage a simple for loop and string concatenation when calling document.getElementById(). I would suggest creating a function to calculate the overtime paid and have the function take the number of weeks as a parameter so that you can easily change it if you add more fields.
function getOvertimePaid(numberOfWeeks) {
var total = 0;
// Iterate from 1 to the number of weeks and increment the total by
// the parsed value in the field for the current index
for (var i=1; i<=numberOfWeeks; i++) {
total += parseFloat(document.getElementById('w_ot_' + i).value.replace(/[^0-9.]/g, '');
}
// Return the annualized amount as a float for flexibility
return (total / numberOfWeeks) * 52;
}
// Update weekly annualised overtime values and provide formatting at this point
document.getElementById("w_annual_ot").value= addCommas(getOvertimePaid(6).toFixed(2));
Another thing you may want to look at to make the code and the supporting HTML even more flexible is to leverage a class name on your weekly overtime input elements. If you do that and adjust the code slightly you can add or remove fields at will and the function to calculate the annualized overtime will continue to work. As an example:
HTML
<input type="text" id="w_ot_1" class="weekly-overtime" value="0.00" />
<input type="text" id="w_ot_2" class="weekly-overtime" value="0.00" />
<input type="text" id="w_ot_3" class="weekly-overtime" value="0.00" />
JavaScript
function getAnnualizedValue(className) {
// Get all elements with the given class name
var elements = document.getElementsByClassName(className);
// Iterate the elements and keep a running total of their values
var total = 0;
for (var i = 0; i < elements.length; i++) {
total += parseFloat((elements[i].value || '0').replace(/[^0-9.]/g, '');
}
// Return the annualized amount as a float for flexibility
return (total / numberOfWeeks) * 52;
}
// Update weekly annualised overtime values and provide formatting at this point
document.getElementById("w_annual_ot").value= addCommas(getAnnualizedValue('weekly-overtime').toFixed(2));
Related
I am working on an app and part of it requires adding values together.
I have a form where a user can enter a dollar amount which allows floats i.e. 55.25 etc... When a a new item is submitted via the form, the totals get added together. Using whole numbers is easy but I want float numbers to be added together on each form submission. The struggle is that to get numbers to display I use parseFloat().toFixed(2) but adding strings together just gives a string value not a mathematical/decimal value.
How can I achieve this?
totalAmount(() => {
let totalPayment = '0.00';
if (items.length > 0) {
for (let i = 0; i < items.length; i++) {
let item = JSON.parse(JSON.stringify(items[i]));
totalPayment = parseFloat(totalPayment) + parseFloat(item.amount).toFixed(2);
}
}
return totalPayment;
}),
Input field
<input type="number" required min="0" id="amount" step=0.01>
You can put a + sign before each item to transform it to numerical and then .toFixed the result
totalPayment = (+totalPayment + +item.amount).toFixed(2)
Add first, then format with toFixed:
totalPayment = parseFloat(totalPayment) + parseFloat(item.amount);
totalPayment = totalPayment.toFixed(2);
Or:
totalPayment = parseFloat(totalPayment) + parseFloat(item.amount);
return totalPayment.toFixed(2);
I figured this next step would be simple but I've been pulling my hair out trying to figure it out. I am putting in an amount of money spent and inputting it via a submit button. As I am putting in multiple values (since I'm also making a list of what the money was spent on) I am trying to get a total of all the money spent, but I either get NaN or just nothing. In theory I am hoping that every time I would hit confirm, the amount of money in the text box would be added to the total for that day.
I've been trying to push the value in an array, then summing it with a for loop but perhaps I'm making this more complicated than it needs to be. Here's my code:
function totalSpent() {
var total= 0;
var spent = document.getElementById("moneySpent").value;
var array = [];
// check if the entered value is number
if (isNaN(Number(spent))) {
alert("Numbers only");
} else {
var spent = parseInt(document.getElementById("moneySpent").value);
for (var i=0; i<spent.length;++i){
array.push(parseFloat(spent[i].value));
}
total = array.reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
});
youSpent.innerHTML=`Total Spent Today: ${total}`;
}
}
<input type="amount" size=25 Placeholder="How much did you spend?"
id="moneySpent">
<input type="button" value="confirm" onClick="totalSpent()">
<br>
<h2 id="youSpent"> Total Spent Today:
</h2>
Here you are my friend, I've made minimal changes to make your code work:
Move array initialization outside of totalSpent()
Only perform array.push(spent) one time, no loop needed
Add an initial value of 0 to array.reduce
var array = [];
function totalSpent() {
var total= 0;
var spent = document.getElementById("moneySpent").value;
// check if the entered value is number
if (isNaN(Number(spent))) {
alert("Numbers only");
} else {
var spent = parseInt(document.getElementById("moneySpent").value);
array.push(spent);
total = array.reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
}, 0);
youSpent.innerHTML=`Total Spent Today: ${total}`;
}
}
<input type="amount" size=25 Placeholder="How much did you spend?"
id="moneySpent">
<input type="button" value="confirm" onClick="totalSpent()">
<br>
<h2 id="youSpent"> Total Spent Today:
</h2>
You have to declare your array out of the function otherwise, each time the function is called, you erased the old values
https://jsfiddle.net/c3L5q6pa/
var array = [];
function totalSpent() {
var spent = parseFloat(document.getElementById("moneySpent").value);
// check if the entered value is number
if (isNaN(spent)) {
return alert("Numbers only");
}
array.push(spent)
const total = array.reduce((previous, current) => previous + current);
youSpent.innerHTML=`Total Spent Today: ${total}`;
})
So, there are 2 things i saw, the first one:
var spent = parseInt(document.getElementById("moneySpent").value);
When you transform your string input value to "parseInt" you lost the String.length property, so your for() won't work.
Second, if you gonna sum all numbers, i dont see the need of push all values to one array then loop it and sum the number, you could do something like:
} else {
total = 0;
var spent = document.getElementById("moneySpent").value;
for (var i=0; i<spent.length;++i) total += parseInt(spent[i]);
youSpent.innerHTML=`Total Spent Today: ${total}`;
}
First, you should declare the array and the total variables outside the function, so they aren't redeclared each time the function is called.
Next, here's my take at simplifying your function, according to how I understand your question:
<input type="amount" size=25 Placeholder="How much did you spend?" id="moneySpent">
<input type="button" value="confirm" onClick="totalSpent()">
<br>
<h2 id="youSpent"> Total Spent Today:
var total = 0;
var array = [];
function totalSpent() {
var spent = document.getElementById("moneySpent").value;
// check if the entered value is number
if (isNaN(Number(spent))) {
alert("Numbers only");
} else {
var spent = parseFloat(document.getElementById("moneySpent").value);
array.push(spent);
total += spent;
document.getElementById('youSpent').innerHTML=`Total Spent Today: ${total}`;
}
}
I have 1 select, 2 text inputs & some JSON data in a form:
select input: List of Suppliers
text input 1: Net Amount
text input 2: Gross Amount
JSON Data:contains the rates of various suppliers as JSON in supplier_tax_rates
I am calculating Gross Amount something like this(pseudo code):
grossAmount = NetAmount + ((currently_selected_supplier.tax_percentage_charged / 100) * netAmount)
Here is the complete code:
Calculate total after retriveing tax rate from JSON
Now, this should work but it doesn't. I get NaN(not a number), means something is wrong. But I have trouble find where.
JSfiddle
You have multiple problems in your code. Here is the correct version:
var taxRates = $.parseJSON(supplier_tax_rates);
var getTaxRate = function(id) {
for (var i in taxRates) { // correct loop definition
if (taxRates[i].id == id) { // check you get id correctly
return taxRates[i].tax_percentage_charged; // instead of 'rate'
}
}
};
$('#PurchaseNetAmount').on('change', function(event) {
var taxRatesId = $('#PurchaseSupplierId').val();
var netAmount = parseFloat(this.value);
var grossAmount = netAmount + ((getTaxRate(taxRatesId) / 100) * netAmount);
$('#PurchaseGrossAmount').val(grossAmount);
});
DEMO: http://jsfiddle.net/A9vmg/18/
Your problem is in the look up function.
for(TaxRate in supplier_tax_rates ){
supplier_tax_rates is a string, not a JSON object
Than after you fix that you will have another error
return rate;
What is rate?
Learn to use console.log() or breakpoints so you can step throught your code and debug it.
getTaxRate(taxRatesId) return undefined
I want to implement a saving system similar to Imgur where if a user presses a button a unique 5 character value is returned. Here is what I have so far:
The database backend uses auto-incrementing ID's starting at 5308416. I use a modified Radix function (see below) to convert these numerical ID's into characters. I use a reverse function to lookup character ID's back to numerical database ID's.
function genID (value)
{
var alphabet = "23456789BCDFGHJKLMNPRSTVWXYZbcdfghjkmnpqrstvwxyz";
var result = "";
var length = alphabet.length;
while (value > 0)
{
result = alphabet[value % length] + result;
value = Math.floor (value / length);
}
return result;
}
The problem is that these generated ID's are very much predictable. My question is, how can I make the generated ID's seem random but still unique (so I can look them up in the database as numbers). I was thinking of using some encryption algorithm but not sure where to start. Any help or suggestions would be appreciated (maybe there is a better way of doing this also).
Do you have to be able to go both ways (i.e. convert an integer to it's hash and back again)? If you can store the hash and lookup the content that way, then it's relatively easy to create a function that produces a hard-to-guess, but complete hash space. You use primes to generate a sequence that only repeats once all possible permutations are exhausted.
The following PHP example is from my own code, adapted from this site:
function hash($len = 6) {
$base = 36;
$gp = array(1,23,809,28837,1038073,37370257 /*,1345328833*/);
$maxlen = count($gp);
$len = $len > ($maxlen-1) ? ($maxlen-1) : $len;
while($len < $maxlen && pow($base,$len) < $this->ID) $len++;
if($len >= $maxlen) throw new Exception($this->ID." out of range (max ".pow($base,$maxlen-1).")");
$ceil = pow($base,$len);
$prime = $gp[$len];
$dechash = ($this->ID * $prime) % $ceil;
$hash = base_convert($dechash, 10, $base);
return str_pad($hash, $len, "0", STR_PAD_LEFT);
}
It would be easy enough to implement that in JavaScript, but ideally you wouldn't need too - you'd have an insert trigger on your table that populated a hash field with the result of that algorithm (adapted for SQL, of course).
A non-predictable, but unique ID can be made by combining your server-side auto-incrementing number with either a current date/time nugget or with a random number. The server-side auto-incrementing number guarantees uniqueness and the date/time nugget or random number removes the predictability.
For a unique ID in string form that takes the server-side unique number as input and where you add the date/time nugget on the client you can do this:
function genID(serverNum) {
return(serverNum + "" + (new Date).getTime());
}
Or using a random number:
function genID(serverNum) {
return(serverNum + "" + Math.floor(Math.random() * 100000));
}
But, it might be best to add the date/time element on the server and just store that whole unique ID in the database there.
I have a page on a site that calculates rate totals for a rental, which are optional. The javascript serves nothing more but to show you the updated total if you select or unselect checkbox options.
Here is what I've tried. It appears to work, but it is adding 2 cents to every other click for one of the checkboxes, I believe because toFixed rounds. How can I keep the number from rounding?
function update_rate(state, amount, field) {
if (state == true) {
rate = parseFloat($('span.rateTotal').text()) + amount;
rate = rate.toFixed(2);
due = parseFloat($('span.'+field).text()) + amount;
due = due.toFixed(2);
$('span.rateTotal').text(rate);
$('span.'+field).text(due);
} else {
rate = parseFloat($('span.rateTotal').text()) - amount;
rate = rate.toFixed(2);
due = parseFloat($('span.'+field).text()) - amount;
due = due.toFixed(2);
$('span.rateTotal').text(rate);
$('span.'+field).text(due);
}
}
Checkbox HTML:
<cfinput type="checkbox" name="linen_service" id="linen_service" checked="checked" value="0" onClick="update_rate(this.checked, #reservationQuery[7].xmlChildren[i]['dblAmount'].xmlText#, 'second-due');" />
Basically passes in the amount of the option, checkbox state, and the name of the field that should be affected.
Edit: Fiddle URL: http://jsfiddle.net/nGrVf/6/
Are you stuck with your your types?
I find it is almost always better to store monetary values in whole numbers of the lowest unit (e.g, cents, or pence) and then add the decimal point two places from the right when displaying.
So the conversions might look like:
var dollars = 100.43;
var cents = Math.round(dollars * 100);
//convert for display
var sCents = String(cents);
var display = sCents.substr(0, sCents.length-2) + "." + sCents.substr(sCents.length-2,2);
alert(display);
Can be seen here at http://jsfiddle.net/jameswiseman76/jhjtP/
Then you don't have to worry about any ugly floating point conversions.
The simplest solution I can think up is to round it down (using muls and floor): i.e.
rate = Math.floor(rate * 100)/100;
Edit: After a bit of testing, I found that there is nothing wrong with the given code. This means the calculation error comes from another part of the code or from the unknown amount variable.