Updating Table Totals with Javascript - javascript

I recently added some functionality to a table using jQuery to allow users to add/delete table rows on the fly which is working well. However in doing so I broke the automatic calculation of totals based on the values enter into some cells in the table rows and for the life of me I can't work out how I broke it nor how to fix it.
I've also noticed that deleting a table row doesn't update the totals either (this was the new feature that I added).
Here's the script that runs that calculates the average number of hours per week for a single row - it should also update the total moderate or high field at the bottom of the table at the same time:
$(window).load(function(){
//Sum Table Cell and Map
$('#lastYear')
.on('change', 'select', calc)
.on('keyup', 'input', calc);
function calc(){
$('#lastYear tr:has(.risk)').each(function(i,v){
var $cel = $(v.cells);
var $risk = $cel.eq(1).find('option:selected').val();
var $numb = $cel.eq(2).find('input').val();
var $weeks = $cel.eq(3).find('input').val();
var $avg = ($numb * $weeks) / 52;
var $avgRounded = Math.round( $avg * 10 ) / 10;
$cel.eq(4).find('input').val($avgRounded);
});
var tot = {high:0,moderate:0};
$('#lastYear tr:has(.risk) option:selected')
.map(function(i){
var el = $(this).val();
var qty = parseFloat($('#lastYear tr:has(.risk)').eq(i).find('td:last').prev().find('input').val());
if (!tot.hasOwnProperty(el)) {
tot[el] = 0;
}
tot[el] += qty
return tot;
}).get();
// console.log(tot);
$('#textfield4').val(tot.moderate.toFixed(1));
$('#textfield5').val(tot.high.toFixed(1));
}
});//]]>
I've setup a jsFiddle that shows the current functionality - you can see if generates the averages but generates a 'NaN' result for the totals when entering data, and when you click the Delete button it should also update the totals too.
Update: I think problem is that the script is looking for the last table cell then going to the previous one to get the value. This used to work when the average cell was the 2nd last cell, but not it's the 3rd last cell and I don't know how to look for that cell by name/id etc. Any ideas?
I'm new to Javascript and have spent almost a day trying to work this out so really appreciate some assistance with this.

Working jsFiddle Demo
You have 2 td after your desired input. So you must call prev method twice:
var qty = parseFloat(
$('#lastYear tr:has(.risk)').eq(i).find('td:last')
.prev().prev() // call prev method twice
.find('input').val()
);

Mark your cells that store the average with eg a CSS class, than use that to find the cell within the row (rather than relying on td:last).
eg:
var row = $('#lastYear tr:has(.risk)').eq(i); // if this is the TR you want..
var avgCell = row.find('td.averageCell'); // find a <TD class="averageCell">.
var avgValue = parseFloat( avgCell.val());
In general, relying on positions to find things is brittle & fairly difficult to maintain; it's better to use IDs (where there is only one) or CSS classes (where there may be multiple.) Both of these are efficient, as well.
Hope this helps!

Related

Using JavaScript to Loop through APEX Application Items

I am working on Oracle APEX, where i have an interactive report to display columns and rows in a tabular form. In the report I have used "apex_item" { each having it's item_id } for most editable columns.
Now, there are three columns, one with the pre-defined read-only value, one where the new value is to be entered and another where the difference between the two would be displayed.
I am not able to write a javascript code to make the above work for all the rows in the report corresponding to those 3 columns. It is only working for the first row for me.
Below is the sample example:
1. APEX_ITEM.TEXT(9,abc, p_item_id=>'p09')
2. APEX_ITEM.TEXT(9,xyz, p_item_id=>'p10')
3. APEX_ITEM.TEXT(9,def,p_attributes =>'readonly', p_item_id=>'p11')
-- document.getElementById("p10").value --> This is only referring to the
value for the first row for that column (p10).
I need item_id 'p11' to reflect the difference of the values of p10 and p09 when i enter the value in p10. Need it to work across all rows for that column.
I am using jQuery here. First add a common classname to the rows of each column. I am here providing same classname as the id.
$('[id]').each(function() {
var ids = $('[id="p09"]');
if (ids.length > 1 && ids[0] == this) {
$('#' + this.id).addClass('p09');
}
var ids = $('[id="p10"]');
if (ids.length > 1 && ids[0] == this) {
$('#' + this.id).addClass('p10');
}
var ids = $('[id="p11"]');
if (ids.length > 1 && ids[0] == this) {
$('#' + this.id).addClass('p11');
}
});
Now you can start a loop over elements like:-
$(".p9").each(function(){
$(this).val() = $(this).siblings(".p11").val() - $(this).siblings(".p10").val();
});
Well, this is how I solved the issue. I am using 'PThis' which is basically a this pointer that refers to each cell in my report. I am using that to find out which row does that particular cell belong to and using that row number i am accessing the other cells where my computation will take effect.
Looking at this function, the code should be self-explanatory.
function change(pThis)
{
var row = pThis.id.split('_')[1];
var xyz= parseFloat(document.getElementById("xyz"+row).value) ;
var abc= parseFloat(document.getElementById("abc"+row).value) ;
var def= parseFloat(xyz)-parseFloat(abc);
def= Math.round(def*100)/100;
document.getElementById("def"+row).value = def;
}

Preventing X numbers from select

I have a script running to show a number in the select list options when the user check one specific value it will display a number refering to how much times he can pay his bill.
Note this code:
var tabelaParcelas = [2,3,4,6,8,10,12];
$(document).ready(function(){
update();
});
$('input[type=checkbox]').click(function(){
update();
})
function update(){
var list = $('#instNum2'); // use selector only once whenever possible for better performance
// clear any existing options from the dropdown list
list.html("")
// count checked boxes
var checked_boxes = 0
$(".check_list").each(function(){
if(this.checked){
checked_boxes++;
}
});
// append options to the select list
for(var i=0;i<checked_boxes;i++){
var option = $("<option>", {value: tabelaParcelas[i], "text": tabelaParcelas[i]});
list.append(option);
}
}
That's correct! But the thing is, I need to display 1x as well, and that's what's not showing at all, 1x should be visible always no matter how much boxes you select, and other thing, when I select more than 7 boxes, the option keep producing empty options, while it should only keep displaying 12x without appending any new...
var tabelaParcelas = [2,3,4,6,8,10,12];
$(document).ready(function(){
update();
});
$('input[type=checkbox]').click(function(){
update();
})
function update(){
var list = $('#instNum2'); // use selector only once whenever possible for better performance
// clear any existing options from the dropdown list
list.html("")
// count checked boxes
var checked_boxes = 0
$(".check_list").each(function(){
if(this.checked){
checked_boxes++;
}
});
//add limit to check_boxes
//This section was not in original code
// Could also do if(checked_boxes > tabelaParcelas.length) {checked_boxes = tabelaParcelas.length;}
//Would make it more dynamic.
//This is added to limit the number of options added to the length of the array at the top.
//This will prevent blank options from being added as requested in the question.
if(checked_boxes > 6) {
checked_boxes = 6;
}
//add 1x option to empty list
//This was not in original code
//This was added as the list was cleared when this function is run and they always wanted 1x to appear as an option.
list.append("<option value='1' selected>1</option>");
// append options to the select list
for(var i=0;i<checked_boxes;i++){
var option = $("<option>", {value: tabelaParcelas[i], "text": tabelaParcelas[i]});
list.append(option);
}
}

Jquery calculating sum with dynamic IDs

I have a google map and when a user adds a marker, it calculates the distance between that marker and the previous marker. I am adding the distances to a table via jQuery. The distances work fine. I want to have an "accumulated distance column where it adds the distances up to that point. So it looks like this:
I am dynamically assigning ids to the spans on each row. I am not sure how to go about creating the accumulated distance column. This is what I have done so far:
var currentIndex=0;
var distancenm = Math.round((((google.maps.geometry.spherical.computeDistanceBetween(FromLocation, ToLocation))/1000)) * 0.539957);
var accdistance = $("#distance_0").val();
var accdistance2 = $("#distance_1").val();
var accdistancetotal = (accdistance+accdistance2);
$('#table').append('<tr id="table_row_'+(currentIndex-1)+'">'+
'<td><span id="distance_'+(currentIndex-1)+'" name="distance_[]" class="distance">'+distancenm+' </span></td>'+
'<td><span id="accdistance_'+(currentIndex-1)+'" name="accdistance_[]" class="accumulateddistance">'+accdistancetotal+' </span></td>'+
'</td>'
I also don't know how to select the ID without directly referencing it like this:
$("#distance_0").val();
because I won't know how many points the user will add. So I need to have it in such a way that each row's accumulated distance column is just the sum of the current row's distance column + the previous row's distance column.
EDIT: It looks like this after Mario's suggestion:
To sum all your current distances you need to do that:
var accDistance = 0;
$('.distance').each(function() {
accDistance += parseInt($(this).text());
});
accDistance += distancenm;
I think it will work because in your example you are using val() in a <span> tag, it is incorrect.

Using On Blur to Call a Function

I am trying to have a web page update a value when the text field loses focus. I have tried a number of different suggested variations for the onblur event but nothing seems to work as expected. Currently I have the onblur in the html code on line 59
<input name="qty1" id="qty1" size="8" value="0" onBlur="productCost()" />
and I have tried to make the correction in the script as well.
function productCosts()
{
var totalMap = document.getElementById("qty1").onblur();
totalMap.value = ("qty1") * ("price1");
//$("#cost1").html (totalMap.toFixed(2));
alert(totalMap)
//var totalPlanner = ('qty2') * ('price2');
//var totalHiker = ('qty3') * ('price3');
}
I have created a fiddle to show the entire program. http://jsfiddle.net/Jn6LQ/ Any help would be really greatly appreciated.
It's easy with jQuery
$('#qty1').bind('blur', productCosts)
or with JS
document.getElementById('qty1').addEventListener('blur', productCosts)
Note: In the below, $ is not jQuery, the OP is using it as a shortcut for getElementById.
The line
totalMap.value = ("qty1") * ("price1");
multiplies the string "qty1" with the string "price1". Perhaps you meant to look up the elements, and then get their values:
totalMap.value = $("qty1").value * $("price1").value;
Separately, using onXyz attributes is usually not best practice. Instead:
$("qty1").onblur = productCosts;
$("price1").onblur = productCosts;
function productCosts() {
var value = $("qty1").value * $("price1").value;
$("cost1").innerHTML = value.toFixed(2);
}
(There I'm assuming the price can be changed as well, but that may not be the case on your page.)
Looking at the fiddle, though, you have a much bigger problem: You want to do that for multiple lines. Using id values to do that is going to make for gainly, over-large code. Instead, use a class on each input, and then relate it to the other inputs in the row using the fact they're all in the same row.
function productCosts() {
var row = this.parentNode.parentNode,
qty = row.querySelector(".qty"),
price = row.querySelector(".price"),
cost = row.querySelector(".cost"),
value = qty.value * price.value;
cost.innerHTML = value.toFixed(2);
}
var list, i;
list = document.querySelectorAll(".qty, .price");
for (i = 0; i < list.length; ++i) {
list[i].onblur = productCosts;
}
jQuery.blur() looks like what you're looking for:
$('#qty1').blur(function(){
alert('here');
});

Calculate total of input text fields on a datatable in jsf

I have a JSF <h:datatable> with two columns.
column 1 : <h:outputText>, gets populated from bean data.
coulmn 2 : <h:inputText> boxes.
There is a "Total" field outside the table and I want to have it show the total of fields as entered in column2 in realtime. So I did searching around and found out that I need a JavaScript to do this. I am however quite new to JS.
Where I am confused is how to access the value of the input text box. What I have done so far:
function totalFrom() {
var element = document.getElementById('transferFundsForm:fundsFromTable:0:from_transferAmt');
if(element != null){
document.forms['transferFundsForm']['transferFundsForm:totalFrom'].value = document.forms['transferFundsForm']['transferFundsForm:totalFrom'].value+ element;
}
}
As far as I understand, the transferFundsForm:fundsFromTable:0, here 0 represents the first row. How do I refer to the element in column that is being edited?
I have called this function on onblur event of the textBox in column.
Also I read that I can use <f:ajax> for this as well, but I am using JSP instead of Facelets, so I can't use <f:ajax>.
The HTML DOM element representation of <table> element has a rows property which gives you an array of all <tr> elements. The HTML DOM representation of this <tr> element has a cells property which gives you an array of all <td> elements.
So, provided that the 2nd column of the table contains only one <input> element which holds the value you'd like to sum up, and that totalFrom is an <input> element (at least, you're attempting to set the value property and not innerHTML), you could achieve this as follows:
function totalFrom() {
var table = document.getElementById('transferFundsForm:fundsFromTable');
var total = 0;
for (var i = 0; i < table.rows.length; i++) {
var secondColumn = table.rows[i].cells[1];
var input = secondColumn.getElementsByTagName('input')[0];
var value = parseInt(input.value);
if (!isNaN(value)) {
total += value;
}
}
document.getElementById('transferFundsForm:totalFrom').value = total;
}
If the totalFrom is however a <h:outputText id="totalFrom">, then set it as follows instead:
document.getElementById('transferFundsForm:totalFrom').innerHTML = total;
Why don't you use the jsf server side event or user
http://livedemo.exadel.com/richfaces-demo/
it also provide you builtin ajax functionality

Categories

Resources