ive a function that does calculations on a table using jquery when any input field is updated. It works fine but i need to be able to call it update a specific row when i load in data. I cant seem to get it working properly either it updates when the an input field changes and it wont work when i call it to update a specific row.
Im trying to pass a parameter into the function to tell what row to update when i need it and when it detects a change event it checks if the variable was passed in. I was trying to check if the passed in variable was undefined or null but i cant seem to get to work. What ami doing wrong?
my code;
so a call to update a certain row;
////////////////////////////////////////////
//load prices and pid from range selected
////////////////////////////////////////////
$(document).ready(function(){
$("#range_select").change(function(event){
//get the range id
$id=$("#range_select").val();
var i;
var loadedValues;
var result;
var pid;
loadedValues=0;
//clear All the prices if loaded, reset background color
$(".price").val(0);
$(".price").css("background-color","#FFF");
//clear ALL product id
$(".productid").val(0);
///////////////////////////////////////////////////////////
//note the url will break if site changed
$.ajax({url:"/mysite/products/list_products_from_range/"+$id, success:function(result){
/*if(result.length==0){
//no results from ajax request
alert('No products found for this range.);
return false;
}*/
//parse the returned JSON object,for each parse of result we check the table
$.each(jQuery.parseJSON(result), function() {
//console.log("product id="+this['Product']['id']);
pid=this['Product']['id'];
var price=this['Product']['price'];
var height=this['Product']['height'];
var width=this['Product']['width'];
/*console.log("price="+price);
console.log("h="+height);
console.log("w="+width);*/
/////////////////////////////////////////////////////////////
//now we have to go through the table and insert the values
i=-1;
var rows = $("#productentry tr:gt(0)"); // skip the header row
rows.each(function(index) {
i++;
var h = $("td:eq(3) .h", this).val();
var w = $("td:eq(4) .w", this).val();
//console.log(h +'x'+w);
//console.log("if "+w+" = "+width+" and "+h+" = "+height);
//console.log('index='+index);
if(w==width && h==height){
//increment count of loaded values
loadedValues++;
//set the price
$("#listprice_"+i).val(price);
//set the pid
//alert(pid);
$("#productid_"+i).val(pid);
//change price textbox to visually show its chnaged
$("#listprice_"+i).css("background-color","#F60");
//update totals (notworking)
calculateTotal(i);
return false;
}
});
/////////////////////////////////////////////////////////////
});
alert('loaded '+loadedValues+' prices');
}});
});//end click event
});
/////////////////////////////////////////////////////
//any input field that changes updates the calculation, not working fully i.e load product prices
/////////////////////////////////////////////////////
$(document).ready(function(){
$(":input").change(calculateTotal);
});
////////////////////////////////////
//calculate total
///////////////////////////////////
var calculateTotal = function(index){
var $discountpercent = null;
var $total=null;
var $quantity=null;
var $id=null;
var $marginpercent=null;
var $margintotal=null;
var myArray=null;
console.log('index='+index + ' indexlen= '+index.length );
if(index === undefined){
console.log('getting id');
//get id of textbox
$id=$(this).attr('id');
//get the row id
$id=$id.toString();
myArray = $id.split('_');
$id=myArray[1];
}
else
{
console.log('setting id=index');
$id=index;
}
var $listprice= $("#listprice_"+$id).val();
//turn entered number into %
$discountpercent= $("#discountpercent_"+$id).val()/100;
$discountlistprice=$listprice-($listprice*$discountpercent);
//turn margin to % (note margin is global)
$marginpercent= $("#marginpercent_"+$id).val()/100;
//apply margin % to DLP
if($discountlistprice>0)
{
$margintotal=$discountlistprice+($discountlistprice*$marginpercent);
}
else
{
$margintotal=0;
}
//set rrp
$rrp=$margintotal;
$("#rrp_"+$id).val($rrp);
//quantity
$quantity=$("#quantity_"+$id).val();
//calculate total
$total=$quantity*$rrp;
//set the value
$("#discountlistprice_"+$id).val($discountlistprice);
//set the total by changing the total div
$("#total_"+$id).html($total);
}
Change your handler to an anonymous function:
$(document).ready(function(){
$(":input").change(function () {
var index = getIndex(); // however you are getting this value
calculateTotal(index);
});
});
Related
I'm working on a GPA calculator, but I've hit a road block.
Here's how the calculator looks like: http://codepen.io/m6cheung/pen/KdWGxa.
Here is the JS part of it:
var $units = $('.units');
var $grade = $('.grade-select');
var $gpa = $('#gpa');
var sum = 0;
$('.btn').click(function() {
$('.block').last().clone().children().val("").parent().appendTo($('.inner-box'));
});
$('.result').hide();
$units.keyup(function() {
$gpa.text((($grade.val() * $(this).val()) / $(this).val()).toFixed(2));
});
$grade.change(function() {
$gpa.text((($units.val() * $(this).val()) / $units.val()).toFixed(2));
$('.result').show();
});
What I want to know: is there any other way, so I can use jQuery to manipulate further $units and $grade values when I press the Add Course button? For now, it only works for the first set of input values.
after adding a new row the keyup and change events are not bind to them.
try using:-
$(document).on('keyup','.units', function() {
and
$(document).on('change','.grade-select', function() {
EDIT from comment
to add them up, create a new function:
function sumScores(){
var score = 0;
$('.block').each(function(i, element){
var unit = $(element).find('.units').val();
var grade = $(element).find('.grade-select').val();
// do calculation and add to score
});
$gpa.text(score.toFixed(2);
}
then set that function to the keyup/change handler.
$(document).on('keyup','.units', sumScores);
$(document).on('change','.grade-select', sumScores);
Since the inputs are added dynamically, you need to bind events to the closest static parent, such as .outer-box. Binding it to document is bad/costly due to event bubbling. Adding up the inputs is as easy as writing a function that would be called on keyup and change which also eliminates code duplication.
var $oBox = $('.outer-box'),
$gpa = $('#gpa'),
$result = $('.result').hide();
$('.btn').click(function() {
$('.block').last().clone().children().val("").parent().appendTo($('.inner-box'));
});
$oBox.on("keyup", ".units", function() {
$gpa.text(getTotal());
});
$oBox.on("change", ".grade-select", function() {
$gpa.text(getTotal());
//Show $result only if it's hidden
$result.is(":hidden") && $result.show();
});
//The function I stated above
function getTotal() {
var sum = 0;
//Loop thru the units
$('.units').each(function() {
var $this = $(this);
//You must also check if the entered unit is a number
//to avoid operating on non-number inputs
//https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/isNaN
if ( !isNaN($this.val()) ) {
//Input vals are always of type string, so, convert them to numbers
//Multiply the pairs
sum += parseFloat($this.val()||0) * parseFloat($this.parent().find('.grade-select').val()||0);
}
});
//Format the number
return sum.toFixed(2);
}
Your updated pen
I noticed the beginning of your code starts with:
var $units = $('.units');
And your inputs are dynamically generated by cloning.
One reason why your computation only works at first input is because $input only points to the fist input, same with $grade.
Maybe you are expecting that $input will automatically take other input as they are cloned. It is not the case. It does not work like CSS rules.
You need to re-execute the line for every clone like this:
$('.btn').click(function() {
$('.block').last().clone().children().val("").parent().appendTo($('.inner-box'));
$units = $('.units');
$grade = $('.grade-select');
});
To manipulate all values you need to loop all elements like this:
var sum = 0;
for (var n = 0; n < $units.length; n++) {
sum += 1 * $($units[n]).val();//1 * -> is for assurance it adding not concat
//to retreive $grade use $($grade[n]).val()
}
I have a piece of code that creates check boxes in a table in a loop and calls their onclick function. In the onclick function, I try to populate a global array that will be a position holder for the checked check boxes of the table. Also if a row is checked, I have to sum the numbers in a text field of that row(I add this to a variable percentage) and if the variable crosses 100 I have to alert the user and ask him to enter values in the checkbox such that the sum is less than 100.
My problem is that each time I click a check box, the global array gets populated, sum is stored in the variable as expected, but the 'tick' on the check box doesn't come/disappears immediately.
How do I solve this issue?
Code:
{
var tabId=document.getElementById("AmnestyTransTbl");
var tabrows = tabId.getElementsByTagName('tr');
var percentage=0,c,n;
var ar=[];
for(var i=1,c=2;i<=tabrows.length-3;i++,c=c+2)
{
// Create CheckBox
ar[i]=c;
var checkBox = document.createElement("input");
checkBox.setAttribute("type", "checkbox");
checkBox.id='CB'.concat(i);
checkBox.onclick = function ()
{
var tabId1=document.getElementById("AmnestyTransTbl");
var rowInd=getRowIndex(this);
CBValue[rowInd]=this.checked;
n=ar[rowInd-1];
percentage=(parseInt(percentage) + parseInt(tabId1.getElementsByTagName("input")[n].value));
if(parseInt(percentage)>100)
{
alert("Amnesty Percentage,"+percentage+", greater than 0!. Plesase check again.");
this.checked=false;
}
if(this.checked==false)
percentage=parseInt(percentage)-parseInt(tabId1.getElementsByTagName("input")[n].value);
} }
var td = document.createElement("td");
td.appendChild(checkBox);
tabrows[i+1].cells[1].appendChild(td);
}
function getRowIndex(el)
{
while((el=el.parentNode) && el.nodeName.toLowerCase() != 'tr');
if (el)
return el.rowIndex;
}
Got the culprit i guess,
Plz try replacing this
if(parseInt(percentage,10)>100) {
this.checked=false;
}
if(this.checked=false)
{
percentage=parseInt(percentage)-parseInt(tabId1.getElementsByTagName("input")[n].value);
}
with this
if(parseInt(percentage,10)>100) {
this.checked=false;
}
else
{
this.checked=true;
}
if(this.checked==false)
{
percentage=parseInt(percentage)-parseInt(tabId1.getElementsByTagName("input")[n].value);
}
I have a form with four text input elements. Every time one of them is updated, I want the sum of the four text input boxes to be displayed in a div below without the user pushing a button. Here's what I have so far (I got the idea from here [does this only work with select?]):
var getSum = function() {
var email = $('#emailDown').val();
var internet = $('#internetDown').val();
var server = $('#serverDown').val();
var desktop = $('#pcDown').val();
//TODO:Check for integers (not needed with sliders)
var sum = email + internet + server + desktop;
$('totalHoursDown').html(sum);
}
$('#emailDown').change(getSum(event));
$('#internetDown').change(getSum(event));
$('#serverDown').change(getSum(event));
$('#pcDown').change(getSum(event));
Currently, it's not updating. (Don't worry about validating). I'm new to PHP, so I'm not sure if I should be using it in this instance.
You are missing a # or . in your selector, depending on if totalHoursDown is a class or an ID:
$('totalHoursDown').html(sum);
// Should be this if ID
$('#totalHoursDown').html(sum);
// or this if class
$('.totalHoursDown').html(sum);
Update:
I modified the code by jmar777 a bit to make it work. Try this instead:
$(function(){
var $fields = $('#emailDown, #internetDown, #serverDown, #pcDown'),
$totalHoursDown = $('#totalHoursDown');
$fields.change(function() {
var sum = 0;
$fields.each(function()
{
var val = parseInt($(this).val(), 10);
sum += (isNaN(val)) ? 0 : val;
});
$totalHoursDown.html(sum);
});
});
​Here is a working fiddle as well: http://jsfiddle.net/mSqtD/
Try this:
var $fields = $('#emailDown, #internetDown, #serverDown, #pcDown'),
$totalHoursDown = $('#totalHoursDown');
$fields.change(function() {
var sum = 0;
$fields.each(function() { sum += $(this).val(); });
$totalHoursDown.html(sum);
});
Also, in your example, you had $('totalHoursDown').html(sum);, which I'm assuming was intended to be an ID selector (i.e., $('#totalHoursDown').html(sum);.
I found this online:
var x = 0; // count for array length
$("input.placeholder").each(function(){
x++; //incrementing array length
});
var _values = new Array(x); //create array to hold default values
x = 0; // reset counter to loop through array
$("input.placeholder").each(function(){ // for each input element
x++;
var the_default = $(this).val();
var default_value = $(this).val(); // get default value.
_values[x] = default_value; // create new array item with default value
});
var current_value; // create global current_value variable
$('input.placeholder').focus(function(){
current_value = $(this).val(); // set current value
var is_default = _values.indexOf(current_value); // is current value is also default value
if(is_default > -1){ //i.e false
$(this).val(''); // clear value
}
});
$('input.placeholder').focusout(function(){
if( $(this).val() == ''){ //if it is empty...
$(this).val(current_value); //re populate with global current value
}
});
As you can see, it grabs the text within a value attribute and sets it as the default_value. It then checks the current_value against the default.
I'm running into a problem.
In this example, we have an element like:
<input type="text" class="placeholder" value="potato">
If the user focuses and unfocuses the input, it works great - removing and repopulating with "potato".
However, let's say a user enters "ioqiweoiqwe", and then unfocuses the input (fills out the rest of the form"). They then go back to our input and delete all of their text, and click on another field. The input would be re-populated with "ioqiweoiqwe" - when really, we want it to be re-populated with the default_value. How do I manage to do this?
Yours sincerely,
a jQuery nub.
Note: I set up a jsfiddle here... a bit after some comments: http://jsfiddle.net/xmhCz/
I don't really know what the problem with that code is, but it looks like it was written by someone who didn't know much JavaScript. I rewrote the functionality:
$("input.placeholder").each(function() {
var me=$(this);
var defaultValue=me.val();
me.focus(function() {
if(me.val()===defaultValue) {
me.val("");
}
});
me.blur(function() {
if(me.val()==="") {
me.val(defaultValue);
}
});
});
Test it out on JSFiddle.
HTML inputs have defaultValue
I'm trying to disable a button, hide a select list & show some text once a button is clicked... because of how long the javascript can take I am using timeouts to prevent the browser locking & the browser ending it prematurely or presenting a warning... however the code I have doesn't seem to be hiding/disabling/showing the elements once the button is clicked.
Edit: I have confirmed that the elements ARE getting hidden & then reshown, however they are being reshown too early.... the javascript hasn't finished doing what it's doing & they are reshown almost instantly after they are hidden.
Edit 2: Fixed it by moving the code that reshows the select list etc from the "addCatsSICMain" function to the "addCatsSIC" function as so..
if (spot < cats.options.length) {
other code here...
} else {
reshow select list etc code here
}
Here is the code:
This first function is the one that is called once the button is clicked.
function addCatsSICMain() {
// Set elements
var addBtn = document.getElementById('add');
var cat_sel = document.getElementById('cat_sic_sel_wrapper');
var addWait = document.getElementById('addWait');
// Disable add button
addBtn.disabled = true;
// Hide selected list
cat_sel.style.display = 'none';
// Show waiting text
addWait.style.display = 'block';
// Use a timeout function so button can be hid/show when we want successfully & not on function completion
setTimeout(function(){
// Add selected cats
addCatsSIC(0);
// Reshow selected list, reenable add button & hide wwaiting text
addWait.style.display = 'none';
cat_sel.style.display = 'block';
addBtn.disabled = false;
}, 10);
}
function addCatsSIC(spot) {
// Set the search results box
var cats = document.getElementById('cat_sic_list');
// Set the selected categories list that we are adding to..
var sel_cats = document.getElementById('cat_sic_sel');
// Set selcted counter var
var sel_count = 0;
// Set category add failed var
var failed = 0;
// Set batch size for looping
var batchSize = 50;
// Still more to do?
if (spot < cats.options.length) {
// Loop through categories from the search results select box
for (var i = spot; i < spot + batchSize && i < cats.options.length; i++) {
// Check if the cat is selected
if (cats.options[i].selected == true) {
// Set this category's values to some variables
var cat_id = cats.options[i].getAttribute('value');
var cat_name = cats.options[i].text;
if (checkCatSICAdd(cat_id) === false) {
// Now we create the new element
var new_option = document.createElement('option');
// Add attribute
new_option.setAttribute('value',cat_id);
// Create text node
var new_text_node = document.createTextNode(cat_name);
// Append new text node to new option element we created
new_option.appendChild(new_text_node);
// Append new option tag to select list
sel_cats.appendChild(new_option);
} else {
failed++;
}
}
}
var nextBitOfWork = function() { addCatsSIC(spot + batchSize) };
// Hand control back to the browser so it can update the page & not timeout & then restart the function
setTimeout(nextBitOfWork, 50);
}
if (failed > 0) {
// Find out if more than 2 cats were selected
for (var i = 0; i < cats.options.length; i++) {
if (cats.options[i].selected == true) {
sel_count++;
}
if (sel_count == 2) {
break;
}
}
// Give them an alert they have added that category already
/*addedCatSICAlert(sel_count);*/
}
}
Any reason why you are not using jQuery for this. You can disable button, hide select box and show elements by doing the following
$('button').click(function() {
$(this).attr('disabled', 'disabled');
$('select').hide();
$('p').show();
})
check working example at http://jsfiddle.net/N697c/1/
Fixed it by moving the code that reshows the select list etc from the "addCatsSICMain" function to the "addCatsSIC" function as so..
if (spot < cats.options.length) {
other code here...
} else {
reshow select list etc code here...
}