I have the code to total a column, but I have subgroups that already have totals. Can I total each number in the column EXCEPT the gray total rows?
var table = $('#datatable');
var leng = table.find("tr:first").children().length;
// add totals to new row
for (var i = 0; i < leng; i++) {
var total = api
.column(i)
.data()
.reduce(function (a, b) {
// return if it's not a value from the gray row
return intVal(a) + intVal(b);
});
// correct any html mistakes that slip through
if (isNaN(intVal(total)))
total = '';
table.find("tfoot tr:first th").eq(i).html(total);
};
Why not just use the :not selector on the rows() API method and calculate the sum based on the remaining rows? Very small example, add the sum of col#1 to the footer in a callback :
var table = $('#example').DataTable({
drawCallback: function () {
var api = this.api(),
sum = 0;
api.rows(":not('.sgrouptotal')").every(function() {
sum += parseFloat(this.data()[0]);
});
$(api.column(0).footer()).text(sum);
}
});
demo -> http://jsfiddle.net/j38bmagj/
The above should be fairly easy to extend to multiple columns. Calculate the sum for col #4 in the same loop like sum4 += this.data()[4] and so on.
What about just doing that?
i = 0;
$('#datatable tr:first tr').each(function(key, value){
if(!$(this).hasClass("sgrouptotal"){
i += parseInt(value.text());
}
});
Related
I have the following table.
As you can see, for some columns I have to show Average/Total in the table footer. My code works well for columns without special formatting but when there is a special formatting like we have to show NEG for negative values, in that case the calculated value is not right. So I added data-value attribute for all cell. Now I want to access the data-value attribute of each cell for the function in footerCallback.
This is html code of an example cell in table
<td data-value="-3.78" class="red">
NEG
</td>
This is my footerCallback code.
"footerCallback": function(row, data, start, end, display) {
var api = this.api(),
data;
// Remove the formatting to get integer data for summation
var intVal = function(i) {
if (typeof i === 'string') {
//remove most useless characters
i = i.replace(/[\$,\),\-,\%,\NEG]/g, '');
//now replace ( with MIN
i = i.replace('(', 'MIN');
//check if i contains MIN, then remove it and multiply it with -1 to make it a negative number
if (i.includes("MIN")) {
i = i.replace('MIN', '');
i = i * (-1);
}
}
return typeof i === 'string' ? i.replace(/[\$,\),\%,\NEG]/g, '') * 1 : typeof i === 'number' ? i : 0;
};
var functionColumns = [#(string.Join(",", MathableColumns.Where(x => !string.IsNullOrEmpty(x))))];
for (var i = 0; i < functionColumns.length; i++) {
var colIndex = functionColumns[i];
total = api
.column(colIndex)
.data()
.reduce(function(a, b) {
return intVal(a) + intVal(b);
}, 0);
total = total.toFixed(2);
if (total < 0)
{
total = total * -1;
$(api.column(colIndex).footer()).html(
'('+total+')'
);
}
else
{
$(api.column(colIndex).footer()).html(
total
);
}
}
},
I've done some research but could not find solid solution for this.
Have a look at this fiddle - http://live.datatables.net/dovirovo/1/edit, this is doing, I believe, what you want. The key part of the code is:
totalValues = api.column(2).nodes().toArray().map(function(node) {
return $(node).attr('data-value');
});
This collects the jQuery nodes for that column, extracts the attribute, which can then be summed.
This is only doing a sum for the full column, but it should be straightforward to use this as a template to do the rows just on the current page, it just needs blending your original code and this.
I have a function that passes values into another function to perform calculations. I rewrote it from jquery into pure js on account of performance issues existing. The function has multiple for loops and is a bit odd to understand. Basically it starts at a column index (19) and gathers cells starting at the top and once they reach the cell below with the class of subtotal they average the values and return.
Here is my JSFIDDLE
Function that calls the average function:
$(function doIt() {
var el1 = $('#rackPlan1 > thead > tr > th:gt(17):not(.totalRow)');
var x = el1.length;
var starter = 19;
for (i = 0; i < x; i++) {
var divs = $('#rackPlan1 > tbody > tr > td:nth-child(' + starter + ')');
for (var a = 0; a < divs.length; a++) {
var thisDiv = divs[a]; // element
var $thisDiv = $(divs[a]); // jquery object
getAverage($thisDiv, 'subTotal');
}
starter += 1;
}
})
The calculations perform on the cells with the header of Proto A, B, etc. So for instance for bottoms in Proto A the third cell down what should be returned is 1.0 (the average) instead of 0.
I want to grab all the values from the label with class price and add them using jQuery. Now actual webpage is different but to understand the concept I am only putting minimum code here. There are 3 labels for prices, and 1 more for total:
<label class="price">120</label>
<label class="price">250</label>
<label class="price">342</label>
<label id="total"></label>
I read that .each() can be used but I could not understand how to use it for this purpose.
I have uploaded jsfiddle over here http://jsfiddle.net/vivpad/cysjtrh8/1/
Basic example
jQuery(document).ready(function($){
var total = 0;
$('label.price').each(function(){
var value = parseFloat($(this).text());
total += value;
});
$('#total').text(total);
});
DEMO
You could get total price mapping .price elements text:
jQuery(document).ready(function ($) {
$('#total').text(function () {
return $('.price').map(function () {
return +$(this).text()
}).get().reduce(function (pv, cv) {
return pv + cv;
}, 0);
});
});
-jsFiddle-
Note that you need to add jquery to your jsfiddle.
Also - you don't need to use .each - you can use arrays as well. Which simplifies it much and it is more efficient. See here: http://jsfiddle.net/vivpad/cysjtrh8/9
var sum = 0;
var prices = $("label.price");
for (var i = 0; i < prices.length; i++)
sum += parseInt($(prices[i]).text());
$("#total").text(sum);
try this:
jQuery(document).ready(function($){
var total = 0;
$('.price').each(function() {
var temp = $(this).html();
total += parseFloat(temp);
});
$('#total').html(total);
});
JsFiddle
Try:
var labelvalues = $('label').map(function () {
return $(this).text();
}).get();
var total = 0;
for (var i = 0; i < labelvalues.length; i++) {
total += labelvalues[i] << 0;
}
$("#total").text(total);
DEMO
Here I am using map function to translate all items to new array of items. And add the elements in the array.
I am attempting to write a page which has a table where the user can input a number in each cell, it would then display a total of that row with the lowest two values of that row subtracted. The code creates the array, finds the total of the array and the lowest 2 values (low and low2 in the code below). However when I try to take the two lowest values from the total, i get an error. I think i have found the error as testing the values using isNaN i find that the sum of the array is not a number, which doesn't seem to make sense to me. Here is where I got up to with the code:
table = document.getElementsByTagName("tbody")[0];
allrows = table.getElementsByTagName("tr");
for (i=0; i < allrows.length; i++) {
rowTotal = 0;
rowArray =[];
for (ii=0; ii < allrows[i].getElementsByTagName("input").length; ii++) {
rowTotal = rowTotal + Number(allrows[i].getElementsByTagName("input")[ii].value);
rowArray.push(Number(allrows[i].getElementsByTagName("input")[ii].value));
var tots=rowTotal;
}
rowArray.sort(function(a, b){return b-a});
var low = $(rowArray[rowArray.length-2]);
var low2 = $(rowArray[rowArray.length-1]);
rowTotaladj = rowTotal- low - low2;
$(".row-total:eq("+(i-1)+")").html(rowTotaladj);
}
Here is a link to a previous version of the page which correctly displays the total (rowTotal) but does not have the total minus the lowest two values in:
Any explaination as to why the sum is not a number and help with the code would be much appreciated.
Since you're already using jQuery, you can use the following code to achieve what you want:
// When an <input> is changed:
$('table input').on('change', function() {
var sum = 0,
vals = [ ];
$(this).parents('table').find('input').each(function() {
var val = parseInt( $(this).val() ) || 0;
vals.push( val );
sum+= val;
});
// Now sort the array:
vals.sort();
total = sum - vals[0] - vals[1];
$('tfoot td').html( total );
});
jsFiddle Demo
I am really struggling with this, so maybe some of you have some beautiful hints?
What I want to do
I want to create a table with two columns ("name" and "rating"). I've got 5 rows.
2 of these rows should have a random "rating" between 6-10
2 other rows should have a random "rating" between 1-5
1 row (the last one) should have a random rating between 7-10.
Until this point there is no problem: This is my jsFiddle so far: http://jsfiddle.net/HT89v/2/
BUT:
I want to shuffle the "ratings" of the first 4 rows, so that the first two rows don't always have a very high "rating" and the 3rd and 4th row don't always have a very low "rating". I want to randomly shuffle them.
The 5th row should not be affected. .
I tried to implement the .shuffle plugin in the jsfiddle but I have no idea what I am doing wrong.
function noNorm(){
document.getElementById("rating4").innerHTML = [Math.floor(Math.random()*5) + 6];
for (var i = 0; i <= 1; i++){
document.getElementById("rating"+i).innerHTML = [Math.floor(Math.random()*5) + 6];
};
for (var i = 2; i <= 3; i++){
document.getElementById("rating"+i).innerHTML = [Math.floor(Math.random()*5) + 1];
};
};
noNorm();
jQuery(function($){
$('#rating0', '#rating1', '#rating2', '#rating3').shuffle();
});
(function($){
$.fn.shuffle = function() {
return this.each(function(){
var items = $(this).children().clone(true);
return (items.length) ? $(this).html($.shuffle(items)) : this;
});
}
$.shuffle = function(arr) {
for(var j, x, i = arr.length; i; j = parseInt(Math.random() * i), x = arr[--i], arr[i] = arr[j], arr[j] = x);
return arr;
}
})(jQuery);
Thank you very very much!
There are many solutions to shuffle arrays with javascript.
If I understand your problem correcty, this should do the trick: http://jsfiddle.net/HT89v/6/
I shuffle the whole ratings[] array before giving a value to ratings[4] so that the 5th row is not affected.