I need to write a code regarding last 12 months calculation every next month so that when a user enters the value in the current month or in next month he should get the result
here how the calculation goes
CA (jan 14) = (Avg of B.Y. 2001=100 for the past 12 months - 115.76)*100/115.76
CA (jan 14)=( 232.66-115.76)*100/115.76=100.009
so every month if some body enters it we should get the value by the above calculation.
I tried with some sort of coding in JavaScript please checkout in this link
http://jsfiddle.net/kundansingh/SLC5F/
B.Y. 2001=100 = value will be enter by user
Total of 12 Months = total value of last 11 months and current month so 12 months
% Increase over 115.763 = 232.66-115.76
App. CA = ( 232.66-115.76)*100/115.76
i need dynamically for every month if input for next month value also it should show the result... what i have created is for one month ..please help me to sort the issue
In this case I'd really recommend using jQuery to make your life a lot easier, especially since you're going to want to do at least one for loop, if not two.
You need to loop through each row, get the previous 11 values, then do your calculations.
In your jsFiddle, the following code should work. I have edited your jsFiddle accordingly: http://jsfiddle.net/SLC5F/1/
$('tr', '#order-table').each(function() {
var total = 0;
var $rows = $(this).prevAll();
// return if we don't have enough rows
// probably better to just add a class to the active rows instead,
// but it's not my job to format your code.
if ( $rows.length < 13) return;
$rows = $rows.slice(0, 11);
// again, would be better to add a class to active inputs instead of using
// a not() filter. you can do this yourself.
total += parseFloat( $(this).find('input').not('.row-total-input, [readonly]').val() );
$rows.each(function() {
total += parseFloat( $(this).find('input').not('.row-total-input').val() );
});
// return if total isn't a number
if ( isNaN(total) ) return;
var monthly_average = total / 12;
// again, would be better to add classes to these TDs instead of using eq()
// make sure you do this before using this script in a live application.
$('td', this).eq(2).text(total);
$('td', this).eq(3).text(Math.round(monthly_average * 100) / 100);
$('td', this).eq(4).text(Math.round(( monthly_average - 115.763 ) * 100 / 115.764 * 100) / 100);
});
Related
I'm trying to keep my code DRY.
I have two virtually identical methods for calculating the cost of certain products.
The formula is $35 for the first item and $15 for every subsequent item, unless a customer has credits, then the first x items are free where x = customer.credits
I keep the prices in a Setting model like so:
Setting.first_item_cost # Set to 35
Setting.item_cost # Set to 15
The method in ruby looks like this:
def calc_subtotal
output = 0.0
primary = Setting.first_item_cost # 35 - Cost of first item
secondary = Setting.item_cost # 15 - Cost of subsequent items
items.each_with_index do |item, i|
unless i < customer.credits
output += i == 0 ? primary : secondary
end
end
return output
end
Meanwhile on my page I update the subtotals live with JavaScript
let price_prime = parseFloat("#{Setting.first_item_cost}");
let price_other = parseFloat("#{Setting.item_cost}");
let credit = parseInt("#{current_customer.credits}");
function calculatePrice( count ){
var output = 0.0;
if( count < 0 ) count = 0;
for (i = 1; i <= count; i++ ){
var price = ( i == 1 ) ? price_prime : price_other;
output += ( i > credit ) ? price : 0.0;
}
return output;
}
So the formulas are close to identical in the different programing languages. Obviously for security reasons I can't just let the client side JavaScript dictate the price, and I'd rather not have to do an AJAX call every time somebody updates the quantity of their order (though that may be the only solution)
What I want to know is if there's a way to DRY this; perhaps by passing the formula from Ruby to JavaScript?
I am working with javascript and i have a loop that selects all the data rows.
The number of rows can be different each time and I do not want to select ALL rows at a time. I want to get rows in 10% batches so performance is better.
Currently i am trying this approach but needs your suggestion is this is a right approach or if there is any better approach?
var TenPercBatch = 0.1;
// for (i in data) {
for (var i = 0; i < data.length*TenPercBatch; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var emailSent = row[1]; // Second column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
//PRODUCTION EMAIL FORM LINK
var url = "https://www.mysiteformurl-endpoint.com";
UrlFetchApp.fetch(url + '&EMAILADDRESS=' + encodeURIComponent(emailAddress));
AudienceList.getRange(startRow + i, 2).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
Depending on number of rows, there are times when i get output in decimal when i calculate 10% of something manually...like 1000 rows, 10% would be 100..but if I have 5 rows, 10% would be 0.5. Is there any way to get the output in non-decimal closest number only so there are no issues in the code?
Like...if 10% is 0.5 then use 1.....if 10% is 7.5 then select 8...and so on...
Is it possible?
Another question is - How to select next 10% only? As I am looking at my loop, I am thinking it MAY always select same 10% batch.
In math there is a function called ceiling with always rounds non-whole numbers to the next integer, e.g. Math.ceil(3) == 3 and Math.ceil(3.1) == 4.
To be safe, you best want to do something like this, although I am unsure as to why you would want to do this in general.
for(var a = 0; a < 10; a++)
{
for(var i = Math.floor(a*data.length*0.1); i < data.length && i < Math.ceil((a+1)*data.length*0.1); i++)
{
//do stuff within batch
}
//do stuff in between batches
}
The inner loop iterates of the the a-th 10% of the data object. If you just want to iterate over the first 10% just set a to 0 instead of the outer for-loop.
Sure it is, use Math.ceil( ) function :)
the title may be a bit confusing but I'll explain it in detail. I have a table in UI and user can choose date ranges from there like;
monday - {in:"13:00:00",out:"13:59:59"}
tuesday - [{in:"13:00:00",out:"13:59:59"},{in:"14:00:00",out:"14:59:59"}]
user can only choose multiple hour intervals for one day. I already made the grouping the intervals according to their date and combining the intervals like
tuesday- [{in:"13:00:00",out:"14:59:59"},{in:"14:00:00",out:"14:59:59"}]
in the first iteration. But I couldn't figure out how to make it for more than 4 or 5 hour intervals.FYI I'm using lodash for sorting and grouping and moment for converting hours to int.
If user enters 5 intervals for tuesday like [{in:"13:00:00",out:"13:59:59"},{in:"14:00:00",out:"14:59:59"},{in:"15:00:00",out:"15:59:59"},{in:"18:00:00",out:"18:59:59"},{in:"19:00:00",out:"19:59:59"}]
I want ranges to be combined like ;
[{in:"13:00:00",out:"15:59:59"},{in:"18:00:00",out:"19:59:59"}]
Any help or suggestion will be appreciated.
Assuming that your input data is chronological then one way of implementing your reduced time table is this;
var timeSlices = [{in:"13:00:00",out:"13:59:59"},{in:"14:00:00",out:"14:59:59"},{in:"15:00:00",out:"15:59:59"},{in:"18:00:00",out:"18:59:59"},{in:"19:00:00",out:"19:59:59"}],
ts = new Date(),
te = new Date(),
reduced = timeSlices.reduce((p,c) => {p.length ? (ts.setHours(...p[p.length-1].out.split(":")),
te.setHours(...c.in.split(":")),
te-ts <= 1000 ? p[p.length-1].out = c.out
: p.push(c))
: p.push(c);
return p;},[]);
console.log(reduced);
However if the objects with in and out times are located arbitrary in the array then a more conceptual approach like first sorting them according to their in times would be essential. That wouldn't be a big deal though.
Assuming ranges are composed of Moment instances and you wanted to combine any two ranges where the end of one range either overlapped another range or was less than or equal to one second behind the start of another range, this function should be able to combine the ranges
function combineRanges (ranges) {
if (ranges.length <= 1) {
return ranges
}
ranges = ranges.sort(byStart)
var current = ranges[0]
var combined = [current]
for (var i = 1; i < ranges.length; i++) {
var next = ranges[i]
if (current.out.diff(next.in, 'seconds') > 1) {
combined.push(next)
current = next
} else if (current.out.isBefore(next.out)) {
current.out = next.out
}
}
return combined
}
function byStart (a, b) {
return a.in - b.in
}
I am in the process of building a calculator to determine how long a childs colic is going to last.
I have the calculator working correctly just need it to take the value it gets and run it through the array and match the next closest value to the value shown and then reference it to its associated week.
So for instance if you select week 2 and then week 5 the calculation returns childs colic will end in .5614399999999999 weeks. You would then run the .5614 through the wessel_data array and find that .5614 falls in between week 6 and 7. I would then take the next closest week which is week 7 and show that instead of the .5614. So it should say childs colic will end in .64 weeks. Now that it has found the .64 I want it to output the associated weeks so that it would say childs colic will end in 7 weeks.
This is what I have written to find the next associated value but cant get it to work.
function closest (num, wessel_data) {
var curr = wessel_data[0];
var diff = Math.abs (num - curr);
for (var val = 0; val < wessel_data.length; val++) {
var newdiff = Math.abs (num - wessel_data[val]);
if (newdiff < diff) {
diff = newdiff;
curr = wessel_data[val + 1];
}
}
return curr;
}
I also have a fiddle so you can see what I am talking about.
Fiddle
I think you want the index of the wessel_data, not the data itself. That is just for comparing. So in this function set curr = val + 1. Not wessel_data[val + 1].
You aren't using this function at all in your fiddle so it is hard to tell what exactly you are doing.
My advice is to think of what values you want returned given inputs and work backward from there.
as you can see in the picture, it would be silly for the user to have to type in all 5 Requested Brands (as that is not required). Maybe they only want to choose one Requested Brand. As it is currently set up, the subtotal is only calculated if the user enters 5 unit costs and 5 quantities...not good. If they don't enter all 5, subtotal returns NaN.
$("a#full_sub_total").click(function(event){
event.preventDefault();
var first = $("div#total_result").text();
var second = $("div#total_result1").text();
var third = $("div#total_result2").text();
var fourth = $("div#total_result3").text();
var fifth = $("div#total_result4").text();
$("#full_total_results p").text((parseInt(first,10) + parseInt(second,10) + parseInt(third,10) + parseInt(fourth,10) + parseInt(fifth,10)));
});
Any help is greatly appreciated.
I would loop over the total_result fields, and incrementally add their parsed values to a total var:
$("a#full_sub_total").on("click", function(){
var total = 0;
$("div[id^=total_result]").text(function(i,t){
total += parseInt( t, 10 ) || 0;
});
$(".full_total").text("$" + total);
});
Note the main part of all of this:
total += parseInt( t, 10 ) || 0;
When the attempt to parse an integer from the text of the element fails, we return 0 in its place. This will not offset the total value, and will permit us to continue along with out any NaN showing up later.
Demo: http://jsbin.com/axowew/2/edit
Basic technique:
var sum = 0;
var num1 = parseInt(text1, 10);
if (!isNaN(num1)) sum += num1;
// ...
(Loops: even better idea.)
The problem your overall total results in NaN is that anytime one or more of individual line total is empty, it will cause your overall result total to equal NaN in your attempt to add (i.e. #+#=#, #+NaN=Nan)
Simplify solution to your problem:
$('#subtotal').click(function(e) {
e.preventDefault();
// Clear overall total
$('#overallTotal').empty();
// Loop through each line total
$('div.lineTotal').each(function() {
// If line total is not empty, add
if ($(this).text() != ''){
$('#overallTotal').text(parseInt($('#overallTotal').text) += parseInt($(this).text()));
}
});
});