I'm trying to display a dynamic running total on a page. I can fill out the fields, click the add button and it adds it to the page with the correct running total. I add a second and third item. The running total again is updating correctly however all running totals for each line are displaying the total running total. How can I fix this?
ListCtrl
angular.module('MoneybooksApp')
.controller('ListCtrl', function ($scope) {
$scope.transactions = [];
$scope.addToStack = function() {
$scope.transactions.push({
amount: $scope.amount,
description: $scope.description,
datetime: $scope.datetime
});
$scope.amount = '';
$scope.description = '';
$scope.datetime = '';
};
$scope.getRunningTotal = function(index) {
console.log(index);
var runningTotal = 0;
var selectedTransactions = $scope.transactions.slice(0, index);
angular.forEach($scope.transactions, function(transaction, index){
runningTotal += transaction.amount;
});
return runningTotal;
};
});
HTML
<div ng:controller="ListCtrl">
<table class="table">
<thead>
<tr>
<th></th>
<th>Amount</th>
<th>Description</th>
<th>Datetime</th>
<th></th>
</tr>
<tr>
<td><button class="btn" ng:click="addToStack()"><i class="icon-plus"></i></button></td>
<td><input type="number" name="amount" ng:model="amount" placeholder="$000.00" /></td>
<td><input name="description" ng:model="description" /></td>
<td><input name="datetime" ng:model="datetime" /></td>
<td></td>
</tr>
<tr>
<th>Running Total</th>
<th>Amount</th>
<th>Description</th>
<th>Datetime</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng:repeat="transaction in transactions" class="{{transaction.type}}">
<td>{{getRunningTotal($index)}} {{$index}}</td>
<td>{{transaction.amount}}</td>
<td>{{transaction.description}}</td>
<td>{{transaction.datetime}}</td>
<td><button class="btn"><i class="icon-remove"></i></button></td>
</tr>
</tbody>
</table>
</div>
You are not using your variable selectedTransactions in your foreach loop. Your foreach loop is calculating all transactions in $scope.transactions.
$scope.getRunningTotal = function(index) {
console.log(index);
var runningTotal = 0;
var selectedTransactions = $scope.transactions.slice(0, index);
angular.forEach($scope.transactions, function(transaction, index){
runningTotal += transaction.amount;
});
return runningTotal;
};
SNIP:
angular.forEach(selectedTransactions, function(transaction, index){
runningTotal += transaction.amount;
});
Related
I am trying to add Price from table column to a total.
I am having problem adding values such as 10.00 or 5.99. I am able to calculate prices with int values, but not with values 10.00 or 5.99, etc.
Here is what I have below.
var table = document.getElementById("myTable"),
sumVal = 0;
for (var i = 1; i < table.rows.length; i++) {
sumVal = sumVal + parseF(table.rows[i].cells[2].innerHTML);
}
document.getElementById("val").innerHTML = "SubTotal =" + sumVal;
console.log(sumVal);
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
</table>
<span id="val"></span>
You have three issues:
You are grabbing the wrong cell index, indices start at 0:
table.rows[i].cells[1]
You need to call the correct parse function:
parseFloat(table.rows[i].cells[1].innerHTML);
You need to format your output:
"SubTotal = $" + sumVal.toFixed(2);
Update: Added functionality for removing rows.
updateSubTotal(); // Initial call
function updateSubTotal() {
var table = document.getElementById("myTable");
let subTotal = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[1].innerHTML);
}, 0);
document.getElementById("val").innerHTML = "SubTotal = $" + subTotal.toFixed(2);
}
function onClickRemove(deleteButton) {
let row = deleteButton.parentElement.parentElement;
row.parentNode.removeChild(row);
updateSubTotal(); // Call after delete
}
#myTable td {
padding: 0.25em;
}
#val {
display: block;
margin-top: 0.5em;
}
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoodie</td>
<td class="count-me">15.00</td>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
</table>
<span id="val"></span>
You are accessing the incorrect array element and also need to use parseFloat
The cells array is zero-based so you need to use cells[1] to access the second column:
var table = document.getElementById("myTable"),
sumVal = 0;
for (var i = 1; i < table.rows.length; i++) {
sumVal = sumVal + parseFloat(table.rows[i].cells[1].innerHTML);
}
document.getElementById("val").innerHTML = "SubTotal =" + sumVal;
console.log(sumVal);
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td><button onClick="myFunction()">Remove</button></td>
</tr>
</table>
<span id="val"></span>
updateSubTotal(); // Initial call
function updateSubTotal() {
var table = document.getElementById("myTable");
let subTotal = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[1].innerHTML);
}, 0);
let subTotal2 = Array.from(table.rows).slice(1).reduce((total, row) => {
return total + parseFloat(row.cells[2].innerHTML);
}, 0);
document.getElementById("val").innerHTML = "SubTotal = $" + subTotal.toFixed(2);
document.getElementById("val1").innerHTML = subTotal2.toFixed(2);
}
function onClickRemove(deleteButton) {
let row = deleteButton.parentElement.parentElement;
row.parentNode.removeChild(row);
updateSubTotal(); // Call after delete
}
#myTable td {
padding: 0.25em;
}
#val {
display: block;
margin-top: 0.5em;
}
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>M2</th>
<th>Remove</th>
</tr>
<tr>
<td>Hoodie</td>
<td class="count-me">15.00</td>
<td class="count-me">34.00</th>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td class="count-me">22.34</th>
<td><button onClick="onClickRemove(this)">Remove</button></td>
</tr>
</table>
<span id="val"></span>
<span id="val1"></span>
var cell = document.getElementsByClassName("count-me");
var val = 0;
var i = 0;
while (cell[i] != undefined) {
val += parseFloat(cell[i].innerHTML);
i++;
} //end while
document.getElementById("val").innerHTML = parseFloat(val).toFixed(2);
console.log(parseFloat(val).toFixed(2));
<table id="myTable">
<tr>
<th>Item</th>
<th>Price</th>
<th>Remove</th>
</tr>
<tr id="">
<td>Hoddie</td>
<td class="count-me">15.00</td>
<td>
<button onClick="myFunction()">Remove</button>
</td>
</tr>
<tr>
<td>Nike Cap</td>
<td class="count-me">10.99</td>
<td>
<button onClick="myFunction()">Remove</button>
</td>
</tr>
</table>
<span id="val"></span>
The issue I'm having is when I try to update the remaining rows in a table .outerHTML so that the name attributes are sequential. It's necessary as the .net backend expects the array to start at zero and be sequential.
If you have more than one row with entries, then delete a row, when updating the outerHTML the DOM values are removed and everything resets to blank. Is there a way to retain the values entered? It works fine not updating the outerHTML but that won't work for the backend.
https://jsfiddle.net/y2dxus1m/
function addBenefit() {
//gets the table and adds a new row based on length
var tableRef = document.getElementById('benefitsField').getElementsByTagName('tbody')[0];
var myHtmlContent = '<td><input name="Octopus.Newborns.ReceivingBenefits[' + tableRef.rows.length + '].FirstName"></td><td><input name="Octopus.Newborns.ReceivingBenefits[' + tableRef.rows.length + '].LastName"></td><td><input name="Octopus.Newborns.ReceivingBenefits[' + tableRef.rows.length + '].Amount"></td><td><input name="Octopus.Newborns.ReceivingBenefits[' + tableRef.rows.length + '].Source"></td><td><button class="btn btn-primary btn-sm" onclick="removeRow(this)">Remove</button></td>';
var newRow = tableRef.insertRow(tableRef.rows.length);
newRow.innerHTML = myHtmlContent;
}
function removeRow(a) {
var row = a.parentNode.parentNode;
row.parentNode.removeChild(row);
var tableRef = document.getElementById('benefitsField').getElementsByTagName('tbody')[0];
for (var i = 0; i < tableRef.rows.length; i++) {
console.log(tableRef.rows[i].outerHTML)
//Issue is here ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tableRef.rows[i].outerHTML = tableRef.rows[i].outerHTML.replace(/(\[).+?(\])/g, "[" + i + "]");
console.log(tableRef.rows[i].outerHTML)
}
}
<table class="deptTable" id="benefitsField">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Weekly Benefit Amount</th>
<th>Source</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td><input name="Octopus.Newborns.ReceivingBenefits[0].FirstName" /></td>
<td><input name="Octopus.Newborns.ReceivingBenefits[0].LastName" /></td>
<td><input name="Octopus.Newborns.ReceivingBenefits[0].Amount" /></td>
<td><input name="Octopus.Newborns.ReceivingBenefits[0].Source" /></td>
<td><button class="btn btn-primary btn-sm" onclick="removeRow(this)">Remove</button></td>
</tr>
</tbody>
</table>
<button onclick="addBenefit()">Add</button>
Adding the following function to reset the table rows after a row was removed resolved the issue. Fiddle updated
function setIndex() { $("td.index").each(function (index) { $(this).text(++index); }); }
I make a table in a form to enable user to submit several item in one time. I am able to use jquery to get the first row of the value input by user. But when they type in the value in the second row, it show error. I am pretty sure there is something wrong with the array that I am using. I have try 2 methods, both method work but it only takes the value from first row only.
<form>
<table>
<thead>
<tr>
<th>Item Code</th>
<th>Item Name</th>
<th>Status</th>
</tr>
</thead>
<tbody id="entrybody">
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
</tbody>
</table>
</form>
$(function() {
$.post("action.php", function(data) {
$("[name='title']").val(data.title);
$("[name='body']").val(data.body);
}, "json");
setInterval(function() {
var itemlist = new Array;
var count = 1;
var title = $("[name='title']").val();
var body = $("[name='body']").val();
itemlist[count - 1] = {};
$("#productbody tbody tr").each(function() {
var that = $(this);
if (that.find("[name='prd_code']").val().length !== 0) {
/*itemlist.push(code);
itemlist.push(name);
itemlist.push(cond);*/ //method 1
itemlist[count - 1].code = that.find("[name='prd_code']").val();
itemlist[count - 1].name = that.find("[name='prd_name']").val();
itemlist[count - 1].cond = that.find("[name='prd_cond']").val(); //method 2
count++;
}
});
console.log(itemlist);
}, 2000);
});
===== Console message (first row) =====
0:
code: "test_code1"
cond: "test_status1"
name: "test_name1"
I've changed the method of the event to a .change() for this example.
Then I've changed the following code:
var itemlist = new Array;
var title = $("[name='title']").val();
var body = $("[name='body']").val();
$("#productbody tbody tr").each(function(i) {
var that = $(this);
if (that.find("[name='prd_code']").val().length !== 0) {
itemlist[i] = {};
itemlist[i].code = that.find("[name='prd_code']").val();
itemlist[i].name = that.find("[name='prd_name']").val();
itemlist[i].cond = that.find("[name='prd_cond']").val(); //method 2
}
});
One problem was that you use this itemlist[count - 1] = {}; before your foreach statement. so you only created the first object.
Demo
$(function() {
$("#productbody tbody tr input").change(function() {
//setInterval(function() {
var itemlist = new Array;
var title = $("[name='title']").val();
var body = $("[name='body']").val();
$("#productbody tbody tr").each(function(i) {
var that = $(this);
if (that.find("[name='prd_code']").val().length !== 0) {
itemlist[i] = {};
itemlist[i].code = that.find("[name='prd_code']").val();
itemlist[i].name = that.find("[name='prd_name']").val();
itemlist[i].cond = that.find("[name='prd_cond']").val(); //method 2
}
});
console.log(itemlist);
});
//}, 2000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<table id="productbody">
<thead>
<tr>
<th>Item Code</th>
<th>Item Name</th>
<th>Status</th>
</tr>
</thead>
<tbody id="entrybody">
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
</tbody>
</table>
</form>
As far as I understand you want to create an array of the values from all table cells in all rows. Here is a relative simple way to do this without JQuery.
document.addEventListener(`change`, handle);
function handle(evt) {
if (evt.target.name.startsWith(`prd_`)) {
// retrieve all rows
const values = [...document.querySelectorAll(`tbody tr`)]
// map to objects containing row number and values
.map(row => ({
row: row.rowIndex,
values: [...row.querySelectorAll(`[name^='prd_']`)]
.reduce( (acc, val) => ({...acc, [val.name]: val.value}), {})
}))
.filter(val => (val.values.prd_code || ``).trim().length > 0);
document.querySelector(`pre`).textContent = JSON.stringify(values, null, 2);
}
}
<table>
<thead>
<tr>
<th>Item Code</th>
<th>Item Name</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
<tr>
<td><input type="text" name="prd_code"></td>
<td><input type="text" name="prd_name"></td>
<td><input type="text" name="prd_cond"></td>
</tr>
</tbody>
</table>
<pre></pre>
Any help would be greatly appreciated.
What I'm trying to achieve is when a number/text in input into the code box it searches the table, if found increments quantity by one, if not found adds a new row counting the no column by one.
I already a some basic jQuery code.
<input type="text" style="width: 200px" id="code" name="code" />
<input id = "btnSubmit" type="submit" value="Release"/>
<table> <thead>
<tr>
<th>No</th>
<th>Code</th>
<th>Qty</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>4444</td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td>5555</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>6666</td>
<td>1</td>
</tr>
<tr>
<td>4</td>
<td>7777</td>
<td>1</td>
</tr>
</tbody>
</table>
edit: my code.
$(document).ready(function() {
$("#btnSubmit").click(function() {
var code = $("input#code").val()
var table = $("table tbody");
table.find('tr').each(function(i) {
no = $(this).find('td').eq(0).text(),
productId = $(this).find('td').eq(1).text(),
Quantity = $(this).find('td').eq(2).text();
if (productId == code) { //see if product is in table
Quantity = +Quantity + +Quantity; // increase qty
alert('found' + Quantity);
} else {
// Add new row
alert('not found');
}
});
});
});
I put together a JSFiddle for you, and copied the JS code here. I tried to make it as beginner friendly as possible...
$("#btnSubmit").on("click", function(){
numRows = $("tr").length;
for(var i=1 ; i<numRows ; i++){
var code = $("tr:nth-child(" + i + ") td:nth-child(2)").html();
var qty = $("tr:nth-child(" + i + ") td:nth-child(3)").html();
if(code == $("#code").val()){
$("tr:nth-child(" + i + ") td:nth-child(3)").html(parseInt(qty) + 1);
return true;
}
}
$("tbody").append("<tr><td>" + numRows + "</td><td>" + $("#code").val() + "</td><td>1</td></tr>");
return true;
});
I have created a sample code using jQuery. It took me like 10 minutes to figure out what you are trying to achive but I hope I understood you quite well:
HTML Side:
<input type="text" style="width: 200px" id="code" name="code" />
<input id = "btnSubmit" type="submit" value="Release"/>
<table> <thead>
<tr>
<th>No</th>
<th>Code</th>
<th>Qty</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>4444</td>
<td>1</td>
</tr>
<tr>
<td>2</td>
<td>5555</td>
<td>1</td>
</tr>
<tr>
<td>3</td>
<td>6666</td>
<td>1</td>
</tr>
<tr>
<td>4</td>
<td>7777</td>
<td>1</td>
</tr>
</tbody>
</table>
and our JavaScript:
$(document).ready(function() {
var found = false;
$("input#btnSubmit").on("click", function() {
var search_val = $("input#code").val();
$("tr").each(function() {
var obj = $(this);
obj.find("td").each(function() {
if(parseInt($(this).html()) == parseInt(search_val))
{
obj.find("td:nth-of-type(3)").html(parseInt(obj.find("td:nth-of-type(3)").html()) + 1);
found = true;
}
});
})
if(found == false)
{
$("table").append("<tr><td>"+($("tr").length)+"</td><td>"+search_val+"</td><td>1</td></tr>");
}
found = false;
});
});
Here's JSFiddle: http://jsfiddle.net/f17gudfw/4/
I have a table as below. I have to populate the "Amount" field using the "Buy Quantity" and "Market Price" field. Amount = Buy Quantity*Market Price. I am doing something as -
<script>
function populate() {
var rows = document.getElementById("mytable").getElementsByTagName("tr");
for ( var i = 1; i <= rows.length; i++) {
cells = rows[i].getElementsByTagName("td");
for ( var j = 0; j <= cells.length; j++) {
if (j == 1) {
var num1 =parseFloat(cells[1].childNodes[0].value);
var num2 =parseFloat(cells[2].childNodes[0].data);
var num3=num1 * num2;
cells[3].childNodes[0].value = num3.toString();
}
}
}
}
</script>
I can get the values of column1 and column2, but the value in last column is not getting populated. The last line does not seem to work.
cells[3].childNodes[0].value = num3.toString();
What should I change?
The below html code is part of my .jsp file.
<form action="BuyServlet">
<table border="1" cellpadding="5" id="mytable">
<tr>
<th>Stock Name</th>
<th>Buy Quantity</th>
<th>Market Price</th>
<th>Amount</th>
</tr>
<tr>
<td>Stock Name</td>
<td><input type="text" name="quantity" onblur="populate()"></td>
<td>122</td>
<td><input type="text" name="amount">
</d>
</tr>
<tr>
<td>Stock Name</td>
<td><input type="text" name="quantity" onblur="populate()"></td>
<td>111</td>
<td><input type="text" name="amount"></td>
</tr>
</table>
</form>
Basically you are getting the value from the text box (best quantity) and you are using data to get the value of the Market price(better use innerText)
try this (Replace with your code inside loop)
var num1 =parseFloat(cells[1].childNodes[0].value);
var num2 =parseFloat(cells[2].innerText);
var num3=num1 * num2;
cells[3].innerText = num3.toString();
Your code is in need of improvement. In your table, you should have a thead and a tbody sections. This will make it more accessible and easier to ingore the heading row.
<table border="1" cellpadding="5" id="mytable">
<thead>
<tr>
<th>Stock Name</th>
<th>Buy Quantity</th>
<th>Market Price</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr>
<td>Stock Name</td>
<td><input type="text" name="quantity"></td>
<td>122</td>
<td><input type="text" name="amount"></td>
</tr>
<tr>
<td>Stock Name</td>
<td><input type="text" name="quantity"></td>
<td>111</td>
<td><input type="text" name="amount"></td>
</tr>
</tbody>
</table>
</form>
Now with the code, you should be adding the onblur with code, not hardcoded. You are looping through the cells, there is no reason for that. Also there is no need to loop every row when the table is changed. Just calculate the one that changed! Using childNodes can be tricky because of whitespace differences in browsers. Run this code after the table has been rendered.
(function () {
var table = document.getElementById("mytable");
var tbody = table.getElementsByTagName("tbody")[0];
var rows = tbody.getElementsByTagName("tr");
function populateRow (index, addBlurEvent) {
var row = rows[index];
var cells = row.getElementsByTagName("td")
var textboxes = row.getElementsByTagName("input");
var amountTextbox = textboxes[0];
var totalTextbox = textboxes[1];
var costCell = cells[2];
var amount = amountTextbox.value.length>0 ? parseFloat(amountTextbox.value) : 0;
var cost = parseFloat(costCell.innerHTML);
var total = amount * cost;
totalTextbox.value = total;
if (addBlurEvent) {
amountTextbox.onblur = function () { populateRow(index, false); };
}
}
for (i=0;i<rows.length;i++) {
populateRow(i, true);
}
}());
The running fiddle of the above code
I think the error is due to spelling mistake - you have childnodes instead of childNodes on "cells[3].childnodes[0].value = num3.toString();"
Check this fiddle - http://jsfiddle.net/VwU7C/