jQuery calculation updating one row at a time - javascript

So, I'm trying to create a small table for working out the potential winnings of betting on a rubber duck race when each duck has certain odds.
I sort of have this working but have hit a stumbling block...
When the page loads all of the maths is done correctly based on the default value of £10. What I then want to do is allow people to change the amount of money they would like to bet per duck and the potential winnings for that duck only updates automatically.
This is what I have so far:
function calculate_odds(row) {
var winnings = 0;
// Set winnings to 0
var odds = $(row).find('#theodds').attr('data-duckodds'),
// Find the value of the data attribute for a specific td
betting_amount = $('[name="betting-amount"]').val(),
// Find the value entered into an input field
winnings = (parseFloat(odds) / 1 + 1) * betting_amount;
// Work out the winnings based on the odds given.
// Divide first number by 1 as all odds are something to 1 for now, then +1
// Multiply that number by the bet
// For example Bet 30 on 3/1 odds
// 3 / 1 = 3 + 1 = 4 * 30 = 120
$(row).find('.js-winnings').html(winnings.toFixed(2));
// Show the winnings amount in the final td in each row
}
$(document).ready(function() {
$('.lineup tbody tr').each(function() {
// Run the function calculate_odds() initially based on the default value;
calculate_odds();
$(this).find('[name="betting-amount"]').on('keyup', function() {
// Now loop through each row and change the winnings amount if the betting amount is changed
calculate_odds($(this).closest('tr'));
}).trigger('keyup');
})
});
From what I understand (my jQuery is not great), within this line: $(this).find('[name="betting-amount"]').on('keyup', function() { all I should need to do is select the specific row I want to update. Which should be simple right?
Instead what this does is takes the updated value from the first row and then applies as that as you change the later rows.
Can anyone point our where I'm going wrong? You can see the calculator here: http://www.kb-client-area.co.uk/ducks/races/race-1/
Thanks in advance :)

The specific problem you're encountering is where you're setting betting_amount:
betting_amount = $('[name="betting-amount"]').val()
You're looking globally in the document, and so finding the first instance.
Switching it to this makes it work:
betting_amount = $(row).find('[name="betting-amount"]').val()
As an aside: it would be better to use a class instead of an ID for #theodds, as IDs are supposed to be unique per document :)

I think perhaps your 'this' isn't referring to what you think it is in this line: calculate_odds($(this).closest('tr'));
Could you try something along the lines of:
$(this).find('[name="betting-amount"]').on('keyup', function(e) {
// Now loop through each row and change the winnings amount if the betting amount is changed
calculate_odds($(e.target).closest('tr'));
}).trigger('keyup');
})

As I said earlier, element IDs must be unique in a given document. You have the id theodds repeated as many times as the number of rows in your table which makes your HTML invalid! Remove those IDs and you could just work around the data-* that you already have.
function calculate_odds(row) {
row = $(row);
var winnings = 0,
//find the data-* from within the context of the keyup - the row
odds = row.find('[data-duckodds]').attr('data-duckodds'),
//find the entered amount from within the context of the keyup - the row
betting_amount = row.find('[name="betting-amount"]').val(),
//Your math
winnings = (parseFloat(odds) / 1 + 1) * betting_amount;
row.find('.js-winnings').html(winnings.toFixed(2));
}
$(document).ready(function() {
//You don't need an each loop here as the keyup will be triggered on every amount box on load as well.
$('.lineup').on("keyup", "[name='betting-amount']", function() {
calculate_odds($(this).closest('tr'));
})
.find("[name='betting-amount']").keyup();
});
Take a look at this fiddle for a demo.

Related

How to randomise string from an array without having the same output twice in a row

I am trying to generate a random string output from an array that's getting triggered at random times. The issue that I am facing now is, sometimes the same output comes out twice in a row, or even more than two times. I wanted the output to be different every single time it gets triggered. I don't want the next output to be the same as the very previous output. Please take a look at the code below. Thanks!
function randAnnouncement() {
var lastIndex, ann = ["one", "two", "three"];
let randomAnnouncement = ann[Math.floor(Math.random() * ann.length)];
//speakTTS(randomAnnouncement);
console.log(randomAnnouncement);
}
function init() {
var myFunction = function() {
randAnnouncement();
var rand = Math.round(Math.random() * (5000 - 1000)) + 500; // generate new time (between x sec and x + 500"s)
setTimeout(myFunction, rand);
}
myFunction();
}
init();
What you are asking for is a random string generator without replacement on the last selected value. The only way to do this is to store the last value somewhere so you can exclude it or repeat the random selection if the same value is selected.
As the web is stateless (i.e. doesn't remember the last value when the page reloads), I suggest that you create a transient or store the last value and read it again before each test.
Another option is to increase the size of the dataset from which your random selection is made. In your example of only 3 values, there is a 33% chance that the same value is selected again. Whereas if you had say 200 values then there would be only 0.5% change of a repeat value occurring.
I hope that this helps you get a solution that you can use.

Calculations from checkboxes

This is for an Acrobat order form we use at work to calculate the amount of paper needed to print jobs. There are 4 conditions (saddle stitched books, perfect bound books single and double sided, and not books). All use a different formula to calculate paper quantity. I have all the formulas woking as individual programs but am having trouble getting them all together in the order form. My original thought was to put them all into the output field as a long if else statement. Then it occurred to me that I could run them from the checkbox.
Does either of these methods make more sense?
How do I run them from a checkbox and output the answer to field "PaperQty"?
This is the code for saddle stitched books. I want this to run when SS_CB checkbox is checked and the result to show in "PaperQty" field.
// get field values;
var FieldA = this.getField("Qty2").value;
var FieldB = this.getField("NoUp2").value;
var FieldC = this.getField("PageCount2").value;
event.value = ""; // default result;
// test for non-zero divisor;
if(Number(FieldB) != 0) {
event.value = (FieldC * FieldA / 4) / FieldB; // perform division;
event.value = Math.ceil(event.value); // Round up to next larger intiger;
}

using jquery and tablesorter, change the value of a chosen cell

I have a tablesorter table, that fills in correctly. What I am trying to do is to ensure that the cells are not being edited by more than 10% over the original value. For example, if the price field (denoted by id #price) is set to 6.00 in the first cell in the first row, and the next amount is 5.00 in the next row, I want to be able to change either price, or both, but not by more than 10% ( 6 becomes 6.60 for example). here is what I have so far:
$('#tally tr').live ('click', function(){
var tempPrice =0;
tempPrice = $(this).find('#price').val();
// Which selects the correct row and price field and will store that value in tempPrice.
$('#price').change(function(){
var pnew =0;
$('#tally tbody tr').each(function() {
if ($('#price').val() > (tempPrice*1.1)){
pnew = tempPrice*1.1;
$('#price').val(pnew.toFixed(2));
alert("Your cannot raise the price by more than 10%");
}
}); //end of tbody tr function
}); // end of change function
}); // end of new price change function
To change the price and ensure it is not more than the 10%. The functions work to change the first cell, but I cant get the price change function to work if I am changing the second cell. Also, as if this is not complicated enough, if I try to change the second cell first, and then try the first cell, it retains the pnew price from the second cell, and then will update the table with that number (5 as in the example above), then it will update the cell with the correct number (6.60).
How do I get this to work the way I need it to?
EDIT: the price can be lowered as much as the user wants, just not raised by more than 10%.
Firstly you should have 3 variables, one which stores the price, one which is the upper limit (*1.1) and one which is the lower limit (*0.9).
You then need to use $('input').focus() to get the original value and $('input').blur() to run the validation when the user has finished.
The problem is when you have multiple inputs it is hard to keep track of the temp price value as the user could click around, so you need to have a variable which keeps track of the most recent input selector so blur can validate that.
var $current_element;
var temp_price;
var l_price;
var h_price;
$('input').focus(function() {
$current_element = $(this);
temp_price = $(this).value();
});
$('input').blur(function() {
var value = $current_element.value();
h_price = value * 1.1;
l_price = value * 0.9;
// Do validation of prices here and then either alert()
// or set $current_element.value(temp_price)
// If validation fails call $current_element.focus() to return the user there
});
Otherwise check out this option: https://stackoverflow.com/a/10393958/1160747
Oh and as other have mentioned.... ID should be unique to one element, use class for multiple elements!

Can someone help me in jquery addition?

I would like to give points to my users who submit articles based on their articles word count.
But my page has many text area fields. Lets say message1,message2,message3
When the user fill textarea(message1,message2,message3) it will show like this in the bottom.
You have typed x words. Points per word : 0.2. Estimated point: xx
I also want to calculate overall points. So i would like to add points of message1,message2,message3 and display it as overall points.
I'm a jquery noob. So i'm not sure which variable i should call.
Here is the jfiddle code what i have so far.
Can someone help me? Thanks
you can declare a variable to save the value of each word count (initialized in 0):
var count1 = count2 = count3 = 0;
And then do something like:
count1 = data.words;
$('#showData4').html((count1+count2+count3)*0.2);
For each $('#testTextarea').textareaCount() you have, as you can see on this jsfiddle
Your first problem is that you're not storing the scores from the individual text area fields so you have no values to add up for the total score. After you start storing this data, you just have to update the total score area when any of the individual scores change.
Check out this fiddle: http://jsfiddle.net/NFDQ3/6/
Keep the count of every Textfield in an array that you can use to compute the overall sum.
I've edited your code, see the demo here: http://jsfiddle.net/yZb7w/38/
Another solution would be to have something like:
$('#testTextarea3').textareaCount(options3, function(data){
$('#showData3').html("You have typed <b>" + data.words + "</b> words. Points per word : <b> 0.2</b>. Estimated point: <b>" + (0.2 * data.words) +"</b>");
$(this).data("points",(0.2 * data.words));
});
This will store the points value per testTextarea. The next step you will do is have a totalScore textarea or some updating behavior for some component and extract stored scored from all the textAreas like:
$('#testTextarea3').data("points");
You could trigger an event from inside getInfo, then bind to that event from outside your plugin to get the updated count from each textarea. Then, it's just a matter of keeping track of each count and adding them up. See jsfiddle (info object will be logged to the console).

Multiple javascript timeouts - problem with live data fetching

I am building a real-time system which (with a use of websockets) updates a table with live data of different frequencies (can be 3 times per second, can be once every 2 seconds - dependant on the type of data).
I am currently struggling to find a way of letting the user know when a particular field has not been updated in the last 5 seconds. That is, if no new data is fetched, I shouldn't keep the old value there, but rather change it to '--' or something similar.
After a long way to the javascript, final function which updates fields looks like that (extremely simplified):
function changeValue(data){
var fieldId= data.fieldId;
var value = Math.round(data.value);
$('span#'+fieldId).text(value);
}
This function gets called each time a field needs to be changed. I've got between 2 and 40 different fields (dependant on the user) that are changed.
What is the best way of setting timers in order to change the values of the fields to '--' every 5 seconds, if no update has been made?
I would be really grateful for some tips,
Thanks,
Karol.
Since you want to indicate timeout on a per-field basis, you have two obvious options:
Have a global interval timer that ticks over fairly frequently and looks through all of your fields for a timeout.
Have independent timers for each field which just deal with that field.
I think on balance I prefer (1) to (2), because we're only dealing with one interval timer then and it makes the housekeeping simpler.
Since IDs in documents must be unique, we can use your field ID values as a key in a hash (an object) to store last updated times. This is kind of a spin on the previous answer but works on a per-field basis. So here's how we'd set those last updated times:
var lastUpdatedTimes = {};
function changeValue(data){
var fieldId= data.fieldId;
var value = Math.round(data.value);
$('span#'+fieldId).text(value);
lastUpdatedTimes[fieldId] = new Date().getTime();
}
Then you set up an interval timer to check each of them.
function checkFieldsForTimeout(){
var now = new Date.getTime();
// For each ID in lastUpdatedTimes, see if 'now minus
// last updated' is > 5000 and is so, set the field
// text to '--' and remove that entry from the last
// updated list with "delete lastUpdatedTimes[itemId]".
}
Should a timed-out field spring back to life, the "--" will be replaced by some real text again.
By deleting the last updated time from "lastUpdatedTimes" whenever we put "--" into a field, we make sure that the interval timer isn't wasting time processing fields that have already been timed out.
This answer was extended to handling multiple fields after the comment by #Andrew (please see also his answer).
Introduce a property updatedTime, which holds the last time the data was updated, in each data. A periodic timer checks updatedTime for all data and updates the text field if appropriate. The check has to be twice as often as the detection period. Your function changeValue() updates updatedTime and the text field.
function checkData() {
var now = new Date.getTime();
for "each data" {
if (now - data.updatedTime >= 5000) {
var fieldId = data.fieldId;
$('span#'+fieldId).text('--');
}
}
}
function changeValue(data) {
var fieldId = data.fieldId;
var value = Math.round(data.value);
$('span#'+fieldId).text(value);
data.updatedTime = new Date.getTime();
}
// Install periodic timer to check last updates:
setInterval(checkData, 5000 / 2); // interval = half the required detection period

Categories

Resources