SUM Total for Column - javascript

please refer to previous question here: Sum total for column in jQuery
i used Aymen's solution, but i edited it to suite my need. It stopped working, my code as below as seen at jsfiddle: http://jsfiddle.net/unKDk/15/
<table id="sum_table" width="300" border="1">
<tr class="titlerow">
<td>Apple</td>
<td>Orange</td>
<td>Watermelon</td>
<td>Strawberry</td>
<td>Total By Row</td>
</tr>
<tr>
<td class="rowAA">1</td>
<td class="rowAA">2</td>
<td class="rowBB">3</td>
<td class="rowBB">4</td>
<td class="totalRow"></td>
</tr>
<tr>
<td class="rowAA">1</td>
<td class="rowAA">2</td>
<td class="rowBB">3</td>
<td class="rowBB">4</td>
<td class="totalRow"></td>
</tr>
<tr>
<td class="rowAA">1</td>
<td class="rowAA">5</td>
<td class="rowBB">3</td>
<td class="rowBB">4</td>
<td class="totalRow"></td>
</tr>
<tr class="totalColumn">
<td class="totalCol">Total:</td>
<td class="totalCol">Total:</td>
<td class="totalCol">Total:</td>
<td class="totalCol">Total:</td>
<td class="totalCol">Total:</td>
</tr>
</table>
Jquery part is
var totals=[0,0,0,0,0];
$(document).ready(function(){
var $dataRows=$("#sum_table tr:not('.totalColumn, .titlerow')");
$dataRows.each(function() {
$(this).find('.rowAA').each(function(i){
totals[i]+=parseInt( $(this).html());
});
$(this).find('.rowBB').each(function(i){
totals[i]+=parseInt( $(this).html());
});
});
$("#sum_table td.totalCol").each(function(i){
$(this).html("total:"+totals[i]);
});
});
how to solve the problem that caused the jquery calculate wrongly.
how to calculate total by row
i need the class name exactly same.

I am not quite sure what you want, but if you just want to sum all rows by column then see below..
var totalsByRow = [0, 0, 0, 0, 0];
var totalsByCol = [0, 0, 0, 0, 0];
$(document).ready(function() {
var $dataRows = $("#sum_table tr:not('.totalColumn, .titlerow')");
$dataRows.each(function(i) {
$(this).find('td:not(.totalRow)').each(function(j) {
totalsByCol[j] += parseInt($(this).html());
totalsByRow[i] += parseInt($(this).html());
});
});
for (var i = 0; i < totalsByCol.length - 1; i++) {
totalsByCol[totalsByCol.length - 1] += totalsByCol[i];
}
$("#sum_table td.totalCol").each(function(i) {
$(this).html("total:" + totalsByCol[i]);
});
$("#sum_table td.totalRow").each(function(i) {
$(this).html("total:" + totalsByRow[i]);
});
});
DEMO

Essentially you want to target all of the td elements that are in the middle rows. Each time you cycle over a new td, you want to add its value to both the last td in its row (unless it is the last td in the row), and also to the td in the last row that shares its index.
$("#sum_table tr:not(:first,:last)").each(function(c,row) {
$("td",row).text(function(i,t) {
var n = parseInt( t, 10 ) || 0;
$(this).nextAll(":last-child").text(function(a,o) {
return n + ( parseInt( o, 10 ) || 0 );
});
$(row).nextAll("tr:last").find("td:nth-child("+(++i)+")").text(function(a,o){
return "Total: " + ( n + ( parseInt( o.replace(/[^\d]/g,""), 10 ) || 0 ) );
});
});
});
​
This should work for any table of any size, not restricting you to x columns, or y rows.
Fiddle: http://jsfiddle.net/unKDk/34/
With Commentary
I would encourage you to read the comments in the example below as they will help you understand what is going on with each line.
// For each table row that is not first or last
$("#sum_table tr:not(:first,:last)").each(function(c,row) {
// For each td within this row
$("td",row).text(function(i,t) {
// Determine numerical value of this td's content
var n = parseInt( t, 10 ) || 0;
// Find last td in this row, change its text
$(this).nextAll(":last-child").text(function(a,o) {
// Increment its value with the value of current TD
return n + ( parseInt( o, 10 ) || 0 );
});
// Find last row, and td within of same index as current td, change its text
$(row).nextAll("tr:last").find("td:nth-child("+(++i)+")").text(function(a,o){
// Increment its value (removing non-numbers) with the value of current td
return "Total: " + ( n + ( parseInt( o.replace(/[^\d]/g,""), 10 ) || 0 ) );
});
// End our td loop
});
// End our tr loop
});

Related

After form is submitted, function runs quickly and chart shows up for a millisecond and then goes away

I have a JavaScript code that I have been trying for a while, where I am trying to get an input text/num with spaces in between and shows a graph of how many "students" received different grades letters. Everything is working great until the last part of the index.js code. When the user writes the scores numbers and clicks the submit button, the graph just shows for a millisecond the information and styles but then it seems like it re-loads again to the beginning. Please help me with the last function.
index.html
<body>
<h1>Grade Distribution</h1>
<div class="center">
<table id="distributionTable">
<tr id="firstRow">
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
<td>F</td>
</tr>
<tr id="thirdRow">
</tr>
</table>
</div>
<section class="center2">
<form id=" ">
<div class="container">
<label class="label-title" for="scores-input">Enter the scores for each studente with space in between: </label>
<input type="text" id="scores-input">
<button onclick="fn1()" id="btn1">Submit</button>
</div>
</form>
</section>
index.js
function parseScores(scoresString) {
return scoresString.split(" "); //Return parsing
}
function buildDistributionArray(scoresArray) {
var result = [0, 0, 0, 0, 0]; //A, B, C, D, F quantities of people who get those grades
for(let i = 0; i < scoresArray.length; i++){
var sco = parseInt(scoresArray[i]);
if(sco >= 90){
result[0] += 1; //sum 1 person to the A place [0] == 1 position
}
else if(sco >= 80){
result[1] += 1; //sum 1 person to the B place [1] == 2 position
}
else if(sco >= 70){
result[2] += 1; //sum 1 person to the C place [2] == 3 position
}
else if(sco >= 60){
result[3] += 1; //sum 1 person to the D place [3] == 4 position
}
else
result[4] += 1; //sum 1 person to the F place [4] == 5 position
}
return result;
}
function setTableContent(userInput) {
var scores = parseScores(userInput); //parse scores from the user input
var arrayGrade = buildDistributionArray(scores); //creating the array of the quantity of people who get the letter grade
var getTable = document.getElementById('distributionTable'); //creating a variable table using the distributionTable id
var flag = 0; //flag in false
var i = 0;
while(i < arrayGrade.length){
if(arrayGrade[i] != 0){ //if the distincts locations of the array is not 0
flag = 1; //flag becomes true
}
i++;
}
if(flag == 1){ //if the flag is true
//create the table rows with the styles
getTable.innerHTML =`
<tr id="firstRow">
<td><div style="height:30px" class="bar0"></div></td>
<td><div style="height:20px" class="bar1"></div></td>
<td><div style="height:10px" class="bar2"></div></td>
<td><div style="height:0px" class="bar3"></div></td>
<td><div style="height:20px" class="bar4"></div></td>
</tr>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
<td>F</td>
</tr>
<tr>
<td class="grade"></td>
<td class="grade"></td>
<td class="grade"></td>
<td class="grade"></td>
<td class="grade"></td>
</tr>`;
var j = 0;
while(j < arrayGrade.length){
var barNames = document.getElementsByClassName("bar"+j); //bar0, bar1, bar2, bar3, bar4
document.getElementsByClassName("grade")[j].innerHTML = arrayGrade[j]; //grade0, grade1, grade2, grade3, grade4
barNames[0].style.height = (arrayGrade[j] * 10)+"px"; //3 * 10 == 30, 1 * 10 = 10; to create the graph height px
j++; //next number from 0 - 4
}
}
else{ //else no table to display
getTable.innerHTML = "<tr><td>No graph to display</td></tr>"; //Printing No Graph To Display
}
}
// The argument can be changed for testing purposes
// setTableContent("45 78 98 83 86 99 90 59 100 200 50 30 20 25 60 65 500 1000");
Help here
function bodyLoaded(input){
setTableContent(input);
}
function fn1(){
const str = document.getElementById('scores-input').value;
// alert("Value inside the text box is: "+str);
bodyLoaded(str);
}
you should add preventDefault to fn1 like this:
function fn1(e){
e.preventDefault();
const str = document.getElementById('scores-input').value;
// alert("Value inside the text box is: "+str);
bodyLoaded(str);
}

assign variable to an individual table cell

I am trying to put images in a table. I have that working, if you click, you cycle through the available options. However, the counter is not cell related, it is a global counter. Is there a way to make a local variable, to keep track of where that individual cell is in the array?
I have tried making a local variable, only to a single cell, but it wasn't working.
Here is the related function in js:
var i = 1;
var table = document.getElementsByTagName('table')[0];
var def = ["tex/white.png", "tex/grass.jpg", "tex/stone.jpg", "tex/water.jpg", "tex/wood.jpg", "tex/lava.jpg"];
table.onclick = function(e) {
var target = (e || window.event).target;
if (target.tagName in { TD: 1, TH: 1 }) {
target.className = "img";
console.log((e || window.event).target);
target.setAttribute('style', 'background-image:' + "url(" + def[i] + ")");
if (i < def.length) {
i++
}
if (i == def.length) {
i = 0;
}
}
};
Here is a working fiddle of what I have done so far:
https://jsfiddle.net/6L0armd4/
The desired result is that I start the array at single cells and it only counts for those cells. At the moment, it always gives the next texture, even when I select a different cell.
A possible solution : using ids to identify each cells, and an object to keep track of which background is currently used for each cells (using their id as key)
<html>
<head>
</head>
<body>
<table>
<tr>
<td id='1'></td>
<td id='2'></td>
<td id='3'></td>
</tr>
<tr>
<td id='4'></td>
<td id='5'></td>
<td id='6'></td>
</tr>
<tr>
<td id='7'></td>
<td id='8'></td>
<td id='9'></td>
</tr>
</table>
</body>
</html>
<script>
var table = document.getElementsByTagName('table')[0];
var def = ["https://cdn1.imggmi.com/uploads/2019/6/19/5e4aedcf566fa5e4501ab584d357be01-full.jpg", "https://cdn1.imggmi.com/uploads/2019/6/19/3d39445ffda6687a6b0e80a69a35fdea-full.jpg"];
var currents = {}
getNextIndex = function(index) {
return index === undefined || index >= def.length - 1 ? 0 : index + 1
}
table.onclick = function(e) {
var target = (e || window.event).target;
if (target.tagName in { TD: 1, TH: 1 }) {
var new_bg_index = getNextIndex(currents[target.id])
currents[target.id] = new_bg_index
target.setAttribute('style', 'background-image:' + "url(" + def[new_bg_index] + ")");
}
};
</script>
you need to make listener event
you may change the color codes to your image path on the below code and avoid any local path image links issue try to use online images direct ones .
var table = document.querySelector('#table')
var selectedCells = table.getElementsByClassName('selected')
table.addEventListener('click', function(e) {
var td = e.target
if (td.tagName !== 'TD') {
return
}
if (selectedCells.length) {
selectedCells[0].className = ''
}
td.className = 'selected'
})
table {
cursor: text;
}
tr {
background-color:white;
}
td {
font-size: 14;
cursor: default;
}
td.selected {
background-color: red;
// replace this with background image tag like this
background-image: url("paper.gif
<table border="1" cellpadding="8" cellspacing="2" id="table">
<tr>
<td>Cell one</td>
<td>Cell Tw</td>
<td>Cell three</td>
<td>Cell Four</td>
<td>Cell five</td>
<td>Cell sex</td>
<td>Cell five</td>
<td>cell seven</td>
<td>cell eight</td>
<td>cell nine</td>
<td>cell tens</td>
<td>cell eleven</td>
<td>cell twelve</td>
</tr>
<tr>
<td>AKo</td>
<td>KK</td>
<td>KQs</td>
<td>KJs</td>
<td>KTs</td>
<td>K9s</td>
<td>K8S</td>
<td>K7s</td>
<td>K6s</td>
<td>K5s</td>
<td>K4s</td>
<td>K3s</td>
<td>K2s</td>

sorting html table with jquery

I have a table in html, I have set for each td an id that I will need to sort the table with a Jquery code.
Sorting works with the FireFox browser, but with Chrome it does not work ... do you know how to help me?
$(function() {
$(".table-user-th").click(function() {
var o = $(this).hasClass('asc') ? 'desc' : 'asc';
$('.table-user-th').removeClass('asc').removeClass('desc');
$(this).addClass(o);
var colIndex = $(this).prevAll().length;
var tbod = $(this).closest("table").find("tbody");
var rows = tbod.find("tr");
rows.sort(function(a, b) {
var A = $(a).find("td").eq(colIndex).attr('id');;
var B = $(b).find("td").eq(colIndex).attr('id');;
if (!isNaN(A)) A = Number(A);
if (!isNaN(B)) B = Number(B);
return o == 'asc' ? A > B : B > A;
});
$.each(rows, function(index, ele) {
tbod.append(ele);
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table border="1">
<thead>
<tr>
<th class="table-user-th">Firstname</th>
<th class="table-user-th">Lastname</th>
</tr>
</thead>
<tbody>
<tr>
<td id="Mark">Mark</td>
<td id="Red">Red</td>
</tr>
<tr>
<td id="Nick">Nick</td>
<td id="Sid">Sid</td>
</tr>
<tr>
<td id="Alex">Alex</td>
<td id="Nirv">Nirv</td>
</tr>
</tbody>
</table>
It seems like there is no purpose of using ids here.
Actually the problem was in you sort function. It should return not just true/false but the numeric difference between two values. As usual it is return -1/0/1
So here I wrote comparator func that does just that. And depending on sort type I just multiply it on -1 or 1.
I've also refactored a little bit your code not to use classes or ids. Using jquery you can use data method that stores data on element by key/value.
$(function() {
function cmp(a,b) {return a < b ? 1 : a > b ? -1 : 0}
$(".sortable-table").on('click', 'th', function() {
var th = $(this);
var colIndex = th.data('column');
if(typeof colIndex === 'undefined') {
return;
}
var sortType = th.data('sort') === 'asc' ? 'desc' : 'asc';
th.data('sort', sortType);
var table = $(this).closest("table");
table.find('thead th').removeClass('asc desc');
th.addClass(sortType);
var tbody = table.find("tbody");
var rows = tbody.find("tr");
rows.sort(function(a, b) {
var A = $(a).find("td").eq(colIndex).text();
var B = $(b).find("td").eq(colIndex).text();
return cmp(A,B) * (sortType === 'asc' ? -1 : 1);
});
$.each(rows, function(index, ele) {
tbody.append(ele);
});
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table border="1" class="sortable-table">
<thead>
<tr>
<th data-column="0">Firstname</th>
<th data-column="1">Lastname</th>
</tr>
</thead>
<tbody>
<tr>
<td>Mark</td>
<td>Red</td>
</tr>
<tr>
<td>Nick</td>
<td>Sid</td>
</tr>
<tr>
<td>Alex</td>
<td>Nirv</td>
</tr>
</tbody>
</table>
Update
Added
var table = $(this).closest("table");
table.find('thead th').removeClass('asc desc');
th.addClass(sortType);

jquery totaling time improperly

So I have the following HTML table on my site
<div class="timecard">
<table>
<tr class = "display-even-row">
<td align="left" style="color:#000099">In</td>
<td align="left" class="job_code">2400-Duffy's</td>
<td align="left" class="hrs">00:04</td>
</tr>
<tr class = "display-odd-row">
<td align="left" style="color:#009900">In</td>
<td align="left" class="job_code">1500-Orchard</td>
<td align="left" class="hrs">01:00</td>
</tr>
<tr class = "display-even-row">
<td align="left" style="color:#000099">In</td>
<td align="left" class="job_code">32-Black</td>
<td align="left" class="hrs">10:00</td>
</tr>
<tr class = "display-odd-row">
<td align="left" style="color:#009900">In</td>
<td align="left" class="job_code">1500-Orchard</td>
<td align="left" class="hrs">4</td>
</tr>
</table>
</div>
<div id="total">
</div>
And I have the following jquery script to calculate the total hours of each individual job code. It is designed dynamically to allow for more job codes to be added later. However, it is not adding up hours properly, but not displaying if a job has minutes.
$(document).ready(function(){
var timeString = $(this).next('td.hrs').text();
var components = timeString.split(':');
var seconds = components[1] ? parseInt(components[1], 10) : 0;
var hrs = parseInt(components[0], 10) + seconds / 60;
total += hrs;
var temp = [];
$('.job_code').each(function(index, element){
var text = $(this).text();
temp.push(text);
});
// remove duplicates
var job_code = [];
$.each(temp, function(index, element){
if($.inArray(element, job_code) === -1) job_code.push(element);
});
var sum = {};
$.each(job_code, function(index, element){
var total = 0;
$('.job_code:contains('+element+')').each(function(key, value){
total += parseInt($(this).next('td.hrs').text());
sum[index] = {'job_code' : element, 'total': total};
});
});
console.log(sum);
$.each(sum, function(index, element){
$('#total').append('<p>Total for '+element.job_code+': '+element.total+'</p>');
});
});
Any thoughts on what changes need to be made to make this work with 00:00 instead of just whole integers? Thanks in advance.
Short of using a date/time parsing library, you'll probably want to extract the integer strings on either side of the colon before you attempt to parse them.
var timeString = $(this).next('td.hrs').text();
var components = timeString.split(':');
var seconds = components[1] ? parseInt(components[1], 10) : 0;
var hrs = parseInt(components[0], 10) + seconds / 60;
total += hrs;
You could also use a regular expression to do this, but the split should work just fine.

dynamic pricing table list

i am writing a code to select/remove the product from display table, and when the product is selected,then product with its price mus be displayed in some other table where at the end sum total is also needed which get updated as per selected product prices
<table id="table-example" class="table">
<thead>
<tr>
<th>Cause</th>
<th>Monthly Charge</th>
</tr>
</thead>
<tbody>
<tr>
<div id="selectedServices"></div>
<td id="myDiv"></td>
</tr>
</tbody>
</table>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<table id="table-example" class="table">
<thead>
<tr>
<th>Cause</th>
<th>Monthly Charge</th>
</tr>
</thead>
<div>
<tbody>
<p>
<tr>
<td>
<input type="checkbox" onclick="ToggleBGColour(this);" />
<label>table</label>
</td>
<td>80</td>
</tr>
<tr>
<td>
<input type="checkbox" onclick="ToggleBGColour(this);" />
<label>chair</label>
</td>
<td>45</td>
</tr>
<tr>
<td>
<input type="checkbox" onclick="ToggleBGColour(this);" />
<label>set</label>
</td>
<td>10</td>
</tr>
</tbody>
</div>
</table>
script
$(function() {
$(":checkbox").change(function() {
var arr = $(":checkbox:checked").map(function() { return $(this).next().text(); }).get();
$("#myDiv").text(arr.join(','));
});
});
function ToggleBGColour(item) {
var td = $(item).parent();
if (td.is('.rowSelected'))
td.removeClass("rowSelected");
else
td.addClass("rowSelected");
}
Here is the corresponding fiddle.
Based on your comment for my other answer, this should work for you then:
$(":checkbox").change(function () {
// Toggle class of selected row
$(this).parent().toggleClass("rowSelected");
// Get all items name, sum total amount
var sum = 0;
var arr = $(":checkbox:checked").map(function () {
sum += Number($(this).parents('tr').find('td:last').text());
return $(this).parents('tr').clone();
}).get();
// Display selected items and their sum
$("#selectedServices").html(arr).find('input').remove();
$("#total").text(sum);
});
This avoids the need for creating new HTML elements in the JavaScript code, and reduces the number of .maps() and .each() loops to one.
http://jsfiddle.net/samliew/uF2Ba/
Here is the javascript for but u need to remove onClick attrs :
$(function() {
$(":checkbox").change(function() {
ToggleBGColour(this);
var arr = $(":checkbox:checked").map(function() {
return $(this).next().text();
}).get();
var nums = $(":checkbox:checked").map(function() {
return parseInt($(this).parent().next().html());
}).get();
var total = 0;
for (var i = 0; i < nums.length; i++) {
total += nums[i] << 0;
}
$("#myDiv").text(arr.join(',') + 'total : '+total);
});
});
function ToggleBGColour(item) {
var td = $(item).parent();
if (td.is('.rowSelected'))
td.removeClass("rowSelected");
else
td.addClass("rowSelected");
}
I updated your fiddle with my answer : http://jsfiddle.net/A2SKr/9/
Here's what i've changed.
Slightly better formatted.
i removed the onclick attribute. Its bad practice to use this because of performance issues. Use delegates
Ive also changed a lil bit of your HTML. the output is now a table
added a total element to the output as well
javascript code :
$(":checkbox").change(function () {
var total = 0;
var check = $(":checkbox:checked");
var causes = check.map(function () {
return $(this).next().text();
}).get();
var costs = check.map(function () {
return $(this).parent().next().text()
}).get();
var tbody = $("#table-example tbody").empty();
$.each(causes, function (i, cause) {
tbody.append("<tr><td>" + cause + "</td><td id='" + i + "'><td/></tr>");
});
$.each(costs, function (i, cost) {
$('#' + i + '').html(cost);
total += parseInt(cost, 10);
});
tbody.append("<tr><td>Total</td><td>" + total + "<td/></tr>");
});
});

Categories