How to get order total if quantity is updated - javascript

Order entry form contains product name, price and quantity columns:
<table id="order-products" class="mobileorder-table">
<colgroup>
<col style="width: 80%;">
<col style="width: 10%;">
<col style="width: 10%;">
</colgroup>
<tbody>
<tr>
<td>
Product1
</td>
<td>
<span class="mobileorder-price">0,98</span>
</td>
<td>
<input data-product="4750211645618" class="quantity" id="product_Soodkogus" name="product.Soodkogus"
type="number" min="0" max="999999" value=""
onblur="orderSumRefresh()" />
</td>
</tr>
</tbody>
</table>
Order total <p id="js-doksumma"></p>
If quantity is changed, order total value should updated. I tried
<script>
function parseFloatFormatted(txt) {
if (typeof txt !== 'string' || txt === null || txt === "") {
return 0
}
return parseFloat(txt.replace(',', '.').replace(' ', ''))
}
function orderSumRefresh() {
let totalAmount = 0
const table = document.getElementById("order-products")
table.rows.forEach((row) => {
//for (let i in table.rows) {
// const row = table.rows[i]
const hind = row.cells[1].querySelector(".mobileorder-price").value
const kogus = row.cells[2].querySelector(".quantity").value
const rowSum = Math.round(parseFloatFormatted(hind)* parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
});
var dok = document.getElementById("js-doksumma")
dok.innerText = totalAmount.toFixed(2)
}
</script>
but got error
How to properly implement this ? Should pure CSS, javascript or query used?
Modern Chrome browser is used in mobile phone, ASP.NET 6 MVC Razor application.

As Nick Vu said a first problem is in the for loop and I changed to:
for (let i = 0; i < table.rows.length; i++) {
I find more problems in the code for example the index of the childNodes is wrong, using
console.log(row.cells[1].childNodes)
you can see there are 3 child and you are searching for the middle one (index: 1)
Then for accessing the data of the input element you need to use the .value property like this:
const kogus = row.cells[2].childNodes[1].value
********************* EDIT *******************
Changing the code as the answer has changed.
For accessing the data of the html element use .innerHTML property.
function parseFloatFormatted(txt) {
if (typeof txt !== 'string' || txt === null || txt === "") {
return 0
}
return parseFloat(txt.replace(',', '.').replace(' ', ''))
}
function orderSumRefresh() {
let totalAmount = 0
const table = document.getElementById("order-products")
/*
for (let i = 0; i < table.rows.length; i++) {
const row = table.rows[i]
const hind = row.cells[1].childNodes[1].innerHTML
const kogus = row.cells[2].childNodes[1].value
const rowSum = Math.round(parseFloatFormatted(hind) * parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
}
*/
for (const row of table.rows) {
const hind = row.cells[1].querySelector(".mobileorder-price").innerHTML
const kogus = row.cells[2].querySelector(".quantity").value
const rowSum = Math.round(parseFloatFormatted(hind)* parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
}
const dok = document.getElementById("js-doksumma")
dok.innerText = totalAmount.toFixed(2)
}
<table id="order-products" class="mobileorder-table">
<colgroup>
<col style="width: 80%;">
<col style="width: 10%;">
<col style="width: 10%;">
</colgroup>
<tbody>
<tr>
<td>
Product1
</td>
<td>
<span class="mobileorder-price">0,98</span>
</td>
<td>
<input data-product="4750211645618" class="quantity" id="product_Soodkogus" name="product.Soodkogus"
type="number" min="0" max="999999" value="" onblur="orderSumRefresh()" />
</td>
</tr>
</tbody>
</table>
Order total <p id="js-doksumma"></p>
I suggest you to use the console.log() and log some variable to see if there is somethink wrong with the code.

Nick is correct. Remember that table.rows is not an array but an HTMLCollection. You can fix the issue simply doing:
const table = document.getElementById("order-products")
for (const row of Array.from(table.rows)) {
}
If you want to see for yourself that there is an "length" property being iterated over, open the dev tools, select the table from the elements tab, and run this snippet in the console:
for (let i in $0.rows) {
console.log(i);
console.log($0.rows[i].cells[0]);
}
You will see the last iteration print "length" and then throw an exception.

Your problem is from here
for (let i in table.rows) {}
The value will be "0" and "length" (not index like your expectation), so it throws an error while trying to access row.cells[0].childNodes (row.cells is undefined)
I'd suggest you modify it to
for (const row of table.rows) {}
The full code can be
function parseFloatFormatted(txt) {
if (typeof txt !== 'string' || txt === null || txt === "") {
return 0
}
return parseFloat(txt.replace(',', '.').replace(' ', ''))
}
function orderSumRefresh() {
let totalAmount = 0
const table = document.getElementById("order-products")
for (const row of table.rows) {
const hind = row.cells[1].childNodes[0].innerHTML
const kogus = row.cells[2].childNodes[0].innerText
const rowSum = Math.round(parseFloatFormatted(hind) * parseFloatFormatted(kogus) * 100) / 100
totalAmount += rowSum
}
const dok = document.getElementById("js-doksumma")
dok.innerText = totalAmount.toFixed(2)
}
<table id="order-products" class="mobileorder-table">
<colgroup>
<col style="width: 80%;">
<col style="width: 10%;">
<col style="width: 10%;">
</colgroup>
<tbody>
<tr>
<td>
Product1
</td>
<td>
<span class="mobileorder-price">0,98</span>
</td>
<td>
<input data-product="4750211645618" class="quantity" id="product_Soodkogus" name="product.Soodkogus" type="number" min="0" max="999999" value="" onblur="orderSumRefresh()" />
</td>
</tr>
</tbody>
</table>
Order total
<p id="js-doksumma"></p>

Related

Get checkbox values with different class name in the same div id - jquery mvc

I am trying to get the values of checkboxes which are in the same divid but have different class name.
<tr>
<td colspan="4" align="center">
<div id="divEntities" style="width:100%;height:150px;overflow-y:scroll;align:center;">
<table cellspacing="2" cellpadding="2" width="95%" align="center" border="1">
#{
var i = 0;
while (i < Model.CompanyMaster.Count)
{
<tr>
<td style="width:50%" hidden="hidden"><input type="checkbox" class="EntityCheck" id="chkCompanyId" /> #Model.CompanyMaster[i].COMPANYID</td>
#if ((i + 1) < Model.CompanyMaster.Count)
{
<td><input type="checkbox" class="EntityCheck" /> #Model.CompanyMaster[i + 1].COMPANY_NAME</td>
<td><input type="checkbox" class="CurrentYear" /> #DateTime.Now.Year </td>
<td><input type="checkbox" class="PreviousYear" /> #DateTime.Now.AddYears(-1).Year </td>
<td><input type="checkbox" class="LastYear" /> #DateTime.Now.AddYears(-2).Year </td>
}
else
{
<td></td>
}
</tr>
i = i + 1;
}
}
</table>
</div>
</td>
</tr>
With above code, I am able to populate data in a table with multiple checkboxes, but unable to get the value of the checkbox where the class name is something other than EntityCheck. Below is my jQuery function:
function GetSelectedEntities() {
var entities = "";
$("#divEntities").find('td').each(function (i, el) {
var checkbox = $(this).find('input.EntityCheck');
//var check1 = $(this).find('CurrentYear');
//var check2 = $(this).find('PreviousYear');
//var check3 = $(this).find('LastYear');
var check1 = $('.CurrentYear').val();
var check2 = $('.PreviousYear').val();
var check3 = $('.LastYear').val();
if (checkbox != undefined && $(checkbox).length > 0 && $(checkbox).prop('checked') == true) {
var EntityData = jQuery.trim($(this).text());
if (entities == "") {
entities = EntityData;
}
else {
entities = entities + "|" + EntityData;
}
}
});
return entities;
}
jQuery function is invoked on a button click event:
<button style="font:normal 9pt Arial;height:30px;width:100px;border-radius:5px; border:none; background-color:royalblue; color:white" id="btnAdd" onclick="GetSelectedEntities(event);">
Add
</button>
I tried by giving the same class name to all the checkboxes but the problem was that I was able to get the values of the year checkbox, even if the CompanyName was not selected. I need the year values only if the CompanyName checkbox is checked and it's corresponding years. I also tried by giving the id='' to the year checkbox, but could not get the values.
I am unable to figure where I am going wrong. What is that I need to change in my jQuery to get the expected result?
Something like this would work:
$('#btnAdd').on('click', function(){
var checked = $('table').find('input:checked');
checked.each(function(){
alert($(this).closest('td').text());
//do your stuff here..
});
});
Se working fiddle: https://jsfiddle.net/c8n4rLjy/
I had to make changes to get the desired solution. Please find the solution below:
<tr>
<td colspan="4" align="center">
<div id="divEntities" style="width:100%;height:150px;overflow-y:scroll;align:center;">
<table cellspacing="2" cellpadding="2" width="95%" align="center" border="1">
#{
var i = 0;
while (i < Model.CompanyMaster.Count)
{
<tr>
<td style="width:50%" hidden="hidden"><input type="checkbox" class="EntityCheck" id="chkCompanyId" /> #Model.CompanyMaster[i].COMPANYID</td>
#if ((i + 1) < Model.CompanyMaster.Count)
{
<td><input type="checkbox" class="EntityCheck" /> #Model.CompanyMaster[i + 1].COMPANY_NAME</td>
<td><input type="checkbox" class="chkYear" /> #DateTime.Now.Year </td>
<td><input type="checkbox" class="chkYear" /> #DateTime.Now.AddYears(-1).Year </td>
<td><input type="checkbox" class="chkYear" /> #DateTime.Now.AddYears(-2).Year </td>
}
else
{
<td></td>
}
</tr>
i = i + 1;
}
}
</table>
</div>
</td>
</tr>
jQuery:
function GetSelectedEntities() {
var entities = "";
var CompanySelected = false;
var counter = 0;
$("#divEntities").find('td').each(function (i, el) {
counter = counter + 1
var checkbox = $(this).find('input.EntityCheck');
var checkboxyear = $(this).find('input.chkYear');
if (counter == 2) {
if (checkbox != undefined) {
if ($(checkbox).prop('checked') == true) {
CompanySelected = true;
var EntityData = jQuery.trim($(this).text());
if (entities == "") {
entities = EntityData;
}
else {
entities = entities + "-" + EntityData;
}
}
else {
CompanySelected = false;
}
}
}
if (counter > 2) {
if (CompanySelected == true) {
if (checkboxyear != undefined) {
if ($(checkboxyear).prop('checked') == true) {
var EntityData = jQuery.trim($(this).text());
entities = entities + "|" + EntityData;
}
}
}
}
if(counter == 5)
{
counter = 0;
}
});
return entities;
}

How to get a table data element using the id?

I can't seem to grab the inner text of an element. I have tried many approaches to this and still can't fully understand why this is not working.
I have already tried grabbing it by the class, by the id and even by the type of element.
I expected the function to run, but instead it gets caught in the problem areas I marked within the javascript.
function updateCartTotal() {
var cartItemContainer = document.getElementById('cart-table')
var cartRows = cartItemContainer.rows.length
var total = 0
for (var i = 1; i < cartRows; i++) {
var cartRow = cartRows[i]
var priceElement = cartRow.getElementById('item-total')[0] //this is the issue ALSO: i have tried removing "[0]"
var quantityElement = cartRow.getElementsByClassName('form-control')[0] //this is the issue ALSO: i have tried removing "[0]"
var price = parseFloat(priceElement.innerText.replace('$', ''))
var quantity = quantityElement.value
total = total + (price * quantity)
}
total = Math.round(total * 100) / 100
document.getElementsByClassName('cart-total-price')[0].innerText = '$' + total
}
<table class="table table-striped table-border checkout-table" id="cart-table">
<tbody>
<tr>
<td class="hidden-xs">
<img src="images/intro-04.jpg" alt="[Rainbow Six] Complete Edition" />
</td>
<td>
<h5 class="txt25">[Rainbow Six] Complete Edition</h5>
</td>
<td class="txt25" id="item-total">
$45.00
</td>
<td>
<input class="form-control" type="number" name="" value="1" max="50" min="1" />
</td>
<td class="item-total-total txt25">
$45.00
</td>
<td><button class="btn btn-danger" onclick="removeRow(this)" type="button">REMOVE</button></td>
</tr>
</tbody>
</table>
getElementById is only on document, not other nodes
document.getElementById('item-total') will return ONE element and
IDs must be unique.
I changed <td class="txt25" id="item-total"> to <td class="txt25 item-total">
I also suggest you change class="cart-total-price" to id="cart-total-price" since there is likely only one
Try classes and querySelector which is superior to getElementsByClassName:
function updateCartTotal() {
[...document.querySelectorAll('cart-table tbody tr')].forEach((cartRow) => {
var price = cartRow.querySelector('.item-total').innerText.replace(/[$\s]/g,"")
var quantity = cartRow.querySelector('.form-control').value;
total += (+price * +quantity)
});
document.querySelector('.cart-total-price').innerText = '$' + total.toFixed(2)
}
For older browser support you can change first line to
var cartRows = document.querySelectorAll('cart-table tbody tr')
for (var i=0, cartRow;i<cartRows.length; i++) {
cartRow = cartRows[i];

Conversion of javascript to jquery (getelementbyid, tagname, innertext, innerhtml)

I have some code written in javascript n when I am trying to convert in jQuery I am getting error.
var holder = document.getElementById('filedetails')
, rows = holder.getElementsByTagName('tr')
setSuccess = function(filename) {
if (holder != null) {
for (i = 0, j = rows.length; i < j; ++i) {
cells = rows[i].getElementsByTagName('td');
if (cells[0].innerText == filename && cells[3].innerText != "error!") {
cells[3].innerHTML = "<a href='#' class='file-delete ss-delete no-click'></a>";
}
}
}
}
I tried
var holder = $('#filedetails"),
rows = $('#filedetails tr")
I am not sure what to do with innertext and innerhtml.
<div data-behavior="delete-process" id="holder">
<table>
<thead>
<tr>
<th class="medium-5">Name</th>
<th class="medium-3">Size</th>
<th class="medium-3">Type</th>
<th class="medium-1"></th>
</tr>
</thead>
<tbody id="filedetails">
<tr data-filesize="1.4" data-filename="Sample Image.jpg">
<td><strong>Sample_Image</strong></td>
<td class="nodesize">1.4 MB</td>
<td>JPG</td>
<td class="file-loading"></td></tr>
</tbody>
</table>
<div class="margin bottom large text-center drag-desc">drag and drop files here.</div>
</div>
Here is a "jqueryized" version of your code
var holder = $('#filedetails'),
rows = holder.find('tr');
var setSuccess = function(filename) {
rows.each(function() {
var cells = $(this).find('td');
if (cells.eq(0).text() == filename && cells.eq(3).text() != "error!") {
cells.eq(3).html("<a href='#' class='file-delete ss-delete no-click'></a>");
}
});
};
setSuccess("Sample_Image");
Alternate that just uses the rows:
var rows = $('#filedetails').find('tr');
var setSuccess = function(filename,useme) {
useme.each(function() {
var cells = $(this).find('td');
if (cells.eq(0).text() == filename && cells.eq(3).text() != "error!") {
cells.eq(3).html("<a href='#' class='file-delete ss-delete no-click'>freebeer</a>");
}
});
};
setSuccess("Sample_Image", rows);
To NOT use a positional table element, use a class and filter by that within the TD cells as here: This assumes one use of a class per row.
var rows = $('#filedetails').find('tr');
var setSuccess = function(filename, useme) {
useme.each(function() {
var cells = $(this).find('td');
if (cells.filter('.file-name').text() == filename
&& cells.filter('.file-loading').text() != "error!") {
cells.filter('.file-loading')
.html("<a href='#' class='file-delete ss-delete no-click'>noclick</a>");
}
});
};
setSuccess("Sample_Image", rows);
Fiddl https://jsfiddle.net/MarkSchultheiss/0fx2jms7/2/
Check the following code snippet
$(document).ready(function(){
var holder = $("#filedetails")
, rows = holder.find('tr');
var rowsLength=rows.Length;
var setSuccess = function(filename) {
if (holder != null) {
var j=rows.length;
for (var i=0; i < j; ++i) {
var cells = $(rows[i]).find('td');
var filename=$('.filename');
var file=$('.file');
if (filename.text() == filename && file.text() != "error!")
{
var aElement=$("<a/>");
aElement.href="#";
aElement.class="file-delete ss-delete no-click";
file.html(aElement);
}
}
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-behavior="delete-process" id="holder">
<table>
<thead>
<tr>
<th class="medium-5">Name</th>
<th class="medium-3">Size</th>
<th class="medium-3">Type</th>
<th class="medium-1"></th>
</tr>
</thead>
<tbody id="filedetails">
<tr data-filesize="1.4" data-filename="Sample Image.jpg">
<td class="filename"><strong>Sample_Image</strong></td>
<td class="nodesize">1.4 MB</td>
<td>JPG</td>
<td class="file-loading file"></td></tr>
</tbody>
</table>
<div class="margin bottom large text-center drag-desc">drag and drop files here.</div>
</div>
Hope this helps

Get value from elements from table

I have the next table:
<table id="table_id">
<tr>
<td>Test</td>
<td>Description</td>
<td>Date</td>
</tr>
<tr>
<td><select>
<option val="1">Math</option>
<option val="2">Chemistry</option>
<option val="3">Biology</option>
</select></td>
<td><input type="text" id="txt_desc"/></td>
<td><input type="text" id="date"/></td>
</tr>
</table>
And the next javascript code for get the values
val_test_op = '';
parent.$('#table_id option:selected').each(function (index,value){
test = $.text(value).trim();
if ( index === 0 && test || index % 1 === 0 && test ) {
val_test_op += index +' TEST: ' + test;
return;
}
})
val_test_input = '';
parent.$('#table_id td>input').each(function (index,value){
test = this.value;
if ( index === 0 && test || index % 2 === 0 && test ) {
texto_examen_input += index +' Description: ' + test;
return;
}
if ( index === 1 && test || index % 3 === 0 && test ) {
texto_examen_input += index +' Date: ' + test;
return;
}
})
My question is: ¿ How i get the value from the option:selected and input text in a only "each function" ?
I don't think you need a each function for getting values from fields in the table.
If you add ids to the fields, you could select those directly with jquery then use the val function to get their values easily.
<table id="table_id">
<tr>
<td>Test</td>
<td>Description</td>
<td>Date</td>
</tr>
<tr>
<td><select id="txt_test">
<option val="1">Math</option>
<option val="2">Chemistry</option>
<option val="3">Biology</option>
</select></td>
<td><input type="text" id="txt_desc"/></td>
<td><input type="text" id="txt_date"/></td>
</tr>
</table>
Then with javascript:
val_test_op = $('#txt_test').val();
texto_examen_desc = $('#txt_desc').val();
texto_examen_date = $('#txt_date').val();
If you really want to use a single each function to get all the values, you could use the :input selector that jquery provides and do the following:
values = '';
$('#table_id').find(':input').each(function (index, input) {
values += $(input).val();
});
I added in a button to alert what the selected value is.
function myFunction(){
var theSelect = document.getElementById("table_id").getElementsByTagName("select")[0];
var selectedOption = theSelect.options[theSelect.selectedIndex].text;
alert(selectedOption);
}
document.getElementById("myButton").addEventListener("click", myFunction, false);
https://jsfiddle.net/e1hxn6kL/
Give your select an ID such as id="opts"
Then
var opts = [];
$.each($("#opts:selected"),function(opt){
opts.push(opt.Val());
}
var txt_desc = $("#txt_desc").Val();
var date = $("#date").Val();
Or similar

Javascript to add values of a table

my HTML code looks like this
<TR Row="1" CLASS="ThemeAlignCenter">
<TD id="wrdActive_Row1" style="width: 50px"
CLASS="rdThemeDataTableCell"><SPAN id="lblactive_Row1">6</SPAN></TD>
... more rows
I want to put a javascript at the end of the page to add all of the the values of lblactive_row1 when ever it appears in the page (in this example the number 6)
Edit: more source
<TABLE style="" border="0" CLASS="rdThemeDataTable" id="dtWardData"
cellspacing="0">
<COL id="wrdActive"></COL>
<COL id="wrdOccupied"></COL>
<TR Row="1" CLASS="ThemeAlignCenter">
<TD id="wrdActive_Row1" style="width: 50px"
CLASS="rdThemeDataTableCell"><SPAN id="lblactive_Row1">4</SPAN></TD>
<TD id="wrdOccupied_Row1" style="width: 50px"
CLASS="rdThemeDataTableCell"><SPAN id="lblOccupied_Row1">4</SPAN></TD>
</TR>
</TABLE>
<TABLE style="" border="0" CLASS="rdThemeDataTable" id="dtWardData"
cellspacing="0">
<COL id="wrdActive"></COL>
<COL id="wrdOccupied"></COL>
<TD id="wrdActive_Row1" style="width: 50px"
CLASS="rdThemeDataTableCell"><SPAN id="lblactive_Row1">6</SPAN></TD>
<TD id="wrdOccupied_Row1" style="width: 50px"
CLASS="rdThemeDataTableCell"><SPAN id="lblOccupied_Row1">2</SPAN></TD>
</TR>
</TABLE>
Repeat...
it goes on like that for another 10 or so tables, all in the same source. editting the html is out of the question because its generated by a third party tool. all i can is add a little script at the end
Depending on whether you're using jQuery or not, you might have to modify your HTML to make it easier to pick out the elements you need.
With jQuery you should be able to do something like this:
var total = 0;
$('table tr.ThemeAlignCenter > td.rdThemeDataTableCell > span').each(function(i) {
total += parseInt($(this).text());
});
Without jQuery, assuming your <table> has an id of data, something along these lines should help:
var tbl = document.getElementById('data');
var cells = tbl.getElementsByTagName('td');
var total = 0;
for (var i = 0, limit = cells.length; i < limit; i++) {
var td = cells[i];
if (td.className === 'rdThemeDataTableCell') {
var elem = td.getElementsByTagName('span')[0];
total += parseInt(elem.innerHTML);
}
}
EDIT: refactored the code so it can be applied to each table (should hopefully work if the table id attributes can't be amended and have to remain identical):
function sumTable(tbl) {
var cells = tbl.getElementsByTagName('td');
var total = 0;
for (var i = 0, limit = cells.length; i < limit; i++) {
var td = cells[i];
if (td.className === 'rdThemeDataTableCell') {
var elem = td.getElementsByTagName('span')[0];
total += parseInt(elem.innerHTML);
}
}
return total;
}
var tables = document.getElementsByTagName('table');
var results = [];
for (var i = 0, limit = tables.length; i < limit; i++) {
var total = sumTable(tables[i]);
results.push(total);
}
Something like this might work:
function totalRows() {
var total = 0;
var spans = document.getElementsByTagName('span');
for(var i=0; i<spans.length; i++) {
if(spans[i].getAttribute('id') === 'lblactive_Row1') {
total += parseInt( spans[i].innerHTML, 10);
}
}
return total;
}
attach totalRows() to an eventHandler

Categories

Resources