Calculate the the value of all EvenChild elements javascript / php - javascript

I have this table, that holds 3 colums , name , price and remove button.
What It needs is a way to calculate the sum of all even childs from the TR parent (every second TD since its the one that contains the price).
I am assuming Javascript will do that but im not sure how its gonna address Even or Odd elements.
I've also thought about using CSS to add some type of markers for the Even or Odd elements and use these markers to guide js but this is beyond my current knowledge.
I searched a lot for a solution to this, but to no avail..
Something along the lines of -
function count() {
var oddchildren = document.getElementByID('#order-table').childNodes.OddchildNodes;
var result = oddchildren + oddchildren;
}
I know this piece of code isnt even nearly proper, its just pseudo-code to represent the basic idea of what we need for the end result.
Here is the JS FIDDLE https://jsfiddle.net/x8usjfs6/

window.addEventListener('DOMContentLoaded', () => {
function calc() {
// get the price elements
let prices = document.querySelectorAll('.price');
// turn them into an array and add up the prices
let total = [].slice
.call(prices)
.reduce((prev, curr) => parseInt(curr.innerText) + prev, 0);
// display the total
document.querySelector('.total').innerHTML = total;
}
function remove(el) {
// keep going up the tree until you find the row
while (el.tagName !== "TR") {
el = el.parentElement;
}
// remove the row
el.remove();
}
// each time a button is clicked, remove a row and
// recalculate the total
function removeAndRecalc() {
remove(this);
calc();
}
// add click listeners to the remove buttons
[].slice
.call(document.querySelectorAll('.remove'))
.forEach(el => el.addEventListener('click', removeAndRecalc));
// calculate the total right off the bat
calc();
});
.price:before {
content: '$'
}
.total:before {
content: '$'
}
<link href="//cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" rel="stylesheet"/>
<table>
<thead>
<tr>
<td>Item</td>
<td>Price</td>
<td></td>
</tr>
</thead>
<tbody>
<tr>
<td>Engineering Suit Level I</td>
<td class="price">100</td>
<td><button class="remove">Remove</button></td>
</tr>
<tr>
<td>Engineering Suit Level I</td>
<td class="price">100</td>
<td><button class="remove">Remove</button></td>
</tr>
<tr>
<td>Standart Plasma Cutter</td>
<td class="price">120</td>
<td><button class="remove">Remove</button></td>
</tr>
<tr>
<td>Standart Plasma Cutter</td>
<td class="price">120</td>
<td><button class="remove">Remove</button></td>
</tr>
<tr>
<td>Total:</td>
<td class="total"></td>
<td></td>
</tr>
</tbody>
</table>

Related

innerHTML to Attribute value Plain JavaScript

Here is my html
<table><thead>
<tr>
<th>Green</th>
<th>Orange</th>
</tr>
</thead>
<tbody>
<tr>
<td>First Stage A</td>
<td>First Stage B</td>
</tr>
<tr>
<td>Second Stage A</td>
<td>Second Stage B</td>
</tr>
</tbody></table>
Expected output
<table><thead>
<tr>
<th>Green</th>
<th>Orange</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Green">First Stage A</td>
<td data-label="Orange">First Stage B</td>
</tr>
<tr>
<td data-label="Green">Second Stage A</td>
<td data-label="Orange">Second Stage B</td>
</tr>
</tbody></table>
Here is the script
var _th = document.querySelectorAll("table th")[0];
var _th_value = _th.innerHTML;
var _td = document.querySelectorAll("table td")[0];
_td.setAttribute("basevalue", _th_value);
How could this to be done through plain JavaScript loop. I tried to figure this out for several hours by my existing JavaScript knowledge. But I couldn’t. Could someone please take a look and give me a hint? Advance thanks.
Step 1: You can first create a mapped array that contains the color values you can collect from the table thead th selector. You need to first convert a HTMLCollection to an array using ES6 Array.prototype.from, and then perform the mapping using Array.prototype.map:
const table = document.querySelector('table');
const colors = Array.from(table.querySelectorAll('thead th')).map(th => th.innerText);
p/s: The reason why innerText is used is so that we don't include any HTML tags, even though in your example innerHTML works just as fine. This is just a personal preference.
Step 2: Then, you simply iterate through all the table tbody tr elements. In each iteration you then iterate through all the td elements you can find, and with their index, use dataset to assign the corresponding color by index:
table.querySelectorAll('tbody tr').forEach(tr => {
tr.querySelectorAll('td').forEach((td, i) => {
td.dataset.color = colors[i];
});
});
See proof-of-concept below, where the cells are colored based on the data-color attribute for ease of visualisation (you can also inspect the DOM to see the correct HTML5 data- attributes are added):
const table = document.querySelector('table');
// Collect colors into an array
const colors = Array.from(table.querySelectorAll('thead th')).map(th => th.innerText);
// Iterate through all `<tr>` elements in `<tbody>
table.querySelectorAll('tbody tr').forEach(tr => {
// Iterate through all `<td>` in a particular row
tr.querySelectorAll('td').forEach((td, i) => {
// Assign color to HTML5 data- attribute
td.dataset.color = colors[i];
});
});
tbody td[data-color="Green"] {
background-color: green;
}
tbody td[data-color="Orange"] {
background-color: orange;
}
<table>
<thead>
<tr>
<th>Green</th>
<th>Orange</th>
</tr>
</thead>
<tbody>
<tr>
<td>First Stage A</td>
<td>First Stage B</td>
</tr>
<tr>
<td>Second Stage A</td>
<td>Second Stage B</td>
</tr>
</tbody>
</table>
var tables = document.getElementsByTagName('table');
for (let table of tables) {
var thead = table.children[0];
var tbody = table.children[1];
var index = 0;
for (let th of thead.children[0].cells) {
var color = th.innerHTML;
for (let tr of tbody.children) {
tr.children[index].setAttribute('data-label', color);
}
index++;
}
}
I had to handle the index outside the for loop because the children elements aren't simple arrays but HTMLCollections, and have different way to iterate over them.
edit: Added loop to iterate over all the tables in the page

how to attempt null.value in document.getelementById

I have a table where it has dynamic rows and I need to get the data and make calculations on it so I get the total number of rows in Javascript and run a loop in it. my table looks like this
<table id='mytable1'>
<tr>
<td id="name_1">Precious Metals</td>
<td id="price_1">500</td>
<td id="qty_1">10</td>
</tr>
<tr>
<td id="name_2">Non Precious Metals</td>
<td id="price_2">200</td>
<td id="qty_2">5</td>
</tr>
<tr>
<td id="name_3">Gemstones</td>
<td id="price_3">300</td>
<td id="qty_3">10</td>
</tr>
and my javascript looks like this
<script>
var counter = $('#mytable1 tr').length;
for (i = 1; i <= counter; i++) {
var price = document.getElementById('price_'+i).value;
var qty= document.getElementById('qty'+i).value;
var price_calc = price * qty;
var total_price = total_price + price_calc;
}
</script>
The problem is that if there is one row missed, I mean Admin delete the row #2 and now there will be two rows and when the loop runs and it did not find the row#2 then it throws the error. Please help me or guide me about how should I go with this problem
You can simplify your HTML and make the calculations independent of the number of rows you have in the table. On top of that, jQuery is not necessary.
Documentation in the source.
const table = document.getElementById("mytable1");
// Put all existing rows inside the table in an array
const rows = [...table.getElementsByTagName("tr")];
// Loop through all rows
rows.map( row => {
// Price is in the first cell
const price = parseInt(row.cells[1].innerHTML);
// Quantity is in the second cell
const quantity = parseInt(row.cells[2].innerHTML);
// Calculate total value for each row
const total_price = price * quantity;
console.log(total_price);
});
<table id='mytable1'>
<tr>
<td>Precious Metals</td>
<td>500</td>
<td>10</td>
</tr>
<tr>
<td>Non Precious Metals</td>
<td>200</td>
<td>5</td>
</tr>
<tr>
<td>Gemstones</td>
<td>300</td>
<td>10</td>
</tr>
</table>

Why does this shuffle function only work with 4+ items? JsFiddle included

I have the following code, which shuffles a set of items in the row of a table. However, the shuffle function only works when there are 4+ items:
var parent = $("#parent");
function shuffleRows(parent) {
var rows = parent.children().children(".shuffledtd1");
for (var i = rows.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = rows[i];
rows.eq(i - 1).after(rows[j]);
rows.eq(j - 1).after(temp);
}
}
shuffleRows(parent);
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<table>
<tbody id="parent">
<tr id="node2" class="shufflerow">
<td class="shuffledtd shuffledtd1">AA</td>
<td class="shuffledtd shuffledtd1">BB</td>
<!-- IF I DELETE THIS AND THE FOLLOWING ROW, THE PRIOR 2 ROWS NO LONGER SHUFFLE -->
<td class="shuffledtd shuffledtd1">CC</td>
<td class="shuffledtd shuffledtd1">DD</td>
</tr>
</tbody>
</table>
Full Code: http://jsfiddle.net/d8rkgx0z/
I think it has something to do with this portion of the code:
rows.eq(i - 1).after(rows[j]);
rows.eq(j - 1).after(temp);
but, unfortunately, my skill set simply isn't robust enough to isolate and correct the issue without hours of trial and error.
Thanks in advance for the help!
Instead of calling children twice, just pass in the direct parent of the cells. Also, shuffling the children is a lot easier using jQuery#sort:
var parent = $("#node2"); // parent should be the tr element not the tbody which is in fact a grandparent not a parent
function shuffleChildren(parent) {
parent.children() // get the children of the parent element
.sort(function() { return Math.random() - 0.5; }) // sort them randomly (shuffling)
.appendTo(parent); // add them back to parent so that the shuffling takes effect
}
shuffleChildren(parent);
Example:
var parent = $("#node2"); // parent should be the tr element not the tbody which is in fact a grandparent not a parent
function shuffleChildren(parent) {
parent.children() // get the children of the parent element
.sort(function() { return Math.random() - 0.5; }) // sort them randomly (shuffling)
.appendTo(parent); // add them back to parent so that the shuffling takes effect
}
shuffleChildren(parent);
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<table>
<tbody id="parent">
<tr id="node2" class="shufflerow">
<td class="shuffledtd shuffledtd1">AA</td>
<td class="shuffledtd shuffledtd1">BB</td>
<td class="shuffledtd shuffledtd1">CC</td>
<td class="shuffledtd shuffledtd1">DD</td>
</tr>
</tbody>
</table>
Note: If you want to do this to all rows, then just use jQuery#each:
$("#parent tr").each(function() { // get all tr inside #parent
shuffleChildren($(this)); // shuffle their children
});
BTW, what you're shuffling are cells not rows.
ibrahim mahrir's answer is the more elegant way to do what you're trying to do, but in the interest of helping you understand why your solution wasn't working I'm posting this as well.
The Problem:
The problem you were seeing is because when i = 0, when you do (i - 1) you get negative one, which is not a valid index in your table.
rows.eq(i - 1).after(rows[j]);
The way to make your solution work:
Below is how you could have solved that issue with your existing code:
function shuffleRows(parent) {
var rows = parent.children().children(".shuffledtd1");
// Changed to i >= 0.
for (var i = rows.length - 1; i >= 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = rows[i];
// Changed to just i, instead if i-1.
rows.eq(i).after(rows[j]);
rows.eq(j - 1).after(temp);
}
}
$('button').on('click', function() {
shuffleRows($("#parent"));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody id="parent">
<tr id="node2" class="shufflerow">
<td class="shuffledtd shuffledtd1">AA</td>
<td class="shuffledtd shuffledtd1">BB</td>
<td class="shuffledtd shuffledtd1">CC</td>
</tr>
</tbody>
</table>
<button>Shuffle</button>
This snippet just made two small changes, which I noted in the code, to avoid the negative index problem you had.
Again, there are much more elegant ways to approach this task, but I always get a lot out of understand why something doesn't work, so I wanted you to have an explanation.
Your script can be simplified by great lengths, especially using proper selectors and a random sorter (Covered both cases of sorting td within a tr - or tr within a tbody:
const randomSorter = () => 0.5 - Math.random();
$('.shufflecells tr').each(function() {
$(this).html($('td', this).sort(randomSorter));
});
$('.shufflerows').each(function() {
$(this).html($('tr', this).sort(randomSorter));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<table>
<tbody class="shufflecells">
<tr>
<td>AA</td>
<td>BB</td>
<td>CC</td>
<td>DD</td>
</tr>
</tbody>
</table>
<table>
<tbody class="shufflecells">
<tr>
<td>AA</td>
<td>BB</td>
</tr>
</tbody>
</table>
<table>
<tbody class="shufflerows">
<tr>
<td>AA</td>
</tr>
<tr>
<td>BB</td>
</tr>
<tr>
<td>CC</td>
</tr>
<tr>
<td>DD</td>
</tr>
</tbody>
</table>

Search the table by cell content with jquery and relative referencing

Having such table
<table>
<thead> ... </thead>
<tbody>
<tr class="TableOdd">
<td class="TableCol0"> 1 </td>
<td class="TableCol1"> x </td>
<td class="TableCol2"> x </td>
<td class="TableCol3"> # </td>
</tr>
<tr class="TableEven">
<td>....</td>
</tr>
</tbody>
E.g. each cell has own class indicating it's column number TableCol0,1,2..N
In each row, needed compare the content of the cells in column 1 and 2 and write the result into colum3.
Managed the following script,
$(document).ready(function() {
var toterr = 0;
$('tbody tr.TableEven,tbody tr.TableOdd').each(function() {
var wanted = $(this).find('.TableCol1' ).html();
var actual = $(this).find('.TableCol2' ).html();
//console.log('wanted='+wanted+'=actual='+actual+'=');
if ( wanted == actual ) {
$(this).find('.TableCol3').text('ok');
} else {
$(this).find('.TableCol3').text('ERROR');
toterr++;
}
});
$('#totalerror').text(toterr);
});
It is probably not optimal, but works.
Now have a bit different scenario: Need compare two cells what are before a cell with a specified content (:CMP:), e.g:
<table>
<thead> ... </thead>
<tbody>
<tr class="TableOdd">
<td class="TableCol0"> x </td>
<td class="TableCol1"> x </td>
<td class="TableCol2"> :CMP: </td>
<td class="TableCol3"> etc </td>
</tr>
<tr class="TableEven">
<td class="TableCol0"> N </td>
<td class="TableCol1"> x </td>
<td class="TableCol2"> y </td>
<td class="TableCol3"> :CMP: </td>
</tr>
</tbody>
For each row, need compare cells what are before :CMP:, and replace the :CMP: with the result. e.g.
in the 1st row need compare the x and x and write ok in the cell .TableCol2
in the 2nd row need compare the x and y and write ERROR in the cell .TableCol3
I haven't idea how to modify the above script.
Can easily get the index of the cell that contains ':CMP:' and use the index to reference the previous cells. Or use traverses like prev() or use eq() once index is found.
$('tbody tr').each(function () {
var $cells = $(this).children(),
$cmp = $cells.filter(':contains(":CMP:")'),
cmpIndex = $cells.index($cmp);
// array of values of previous cells
var values = $.map($cells.slice(cmpIndex - 2, cmpIndex), function (el) {
return $.trim($(el).text());
});
// make sure we have 2 cells with values and compare
var cmpText = values.length === 2 && values[0] === values[1] ? 'OK' : 'ERROR';
$cmp.text(cmpText);
});
DEMO

jQuery: How to re-count and re-name elements

I have a list of table rows and these tr's have numbered classes for some reason (leg-1, leg-2 etc). It is already possible to delete a single tr from within this context.
After deleting a tr I need to rename the remaining tr's.
Example:
I have
<tr class="leg-1"></tr>
<tr class="leg-2"></tr>
<tr class="leg-3"></tr>
Now I delete leg-2. Remaining are:
<tr class="leg-1"></tr>
<tr class="leg-3"></tr>
Now I want to rename the remaining tr's, so that it's back to leg-1 and leg-2.
How can this be done??
Thx for any help!
EDIT:
I forgot to mention that it can have more than one tr with class "leg-1", "leg-2" ... So the right starting example would be
<tr class="leg-1"></tr>
<tr class="leg-1"></tr>
<tr class="leg-2"></tr>
<tr class="leg-3"></tr>
<tr class="leg-3"></tr>
Now when I delete leg-2 , both of the tr's with class="leg-3" have to be renamed to be class="leg-2". ..
Sorry I didn't mention this earlier!!
SEE IT IN ACTION
http://jsfiddle.net/Lynkb22n/2/
I'd suggest, at its most straightforward:
$('tr').each(function(i) {
// looking for a class-name that starts with (follows a
// word-boundary: \b) leg- followed by one or more numbers (\d+)
// followed by another word-boundary:
var matchedClass = this.className.match(/\bleg-\d+\b/);
// if a match exists:
if (matchedClass) {
// set the node's className to the same className after replacing
// the found leg-X class name with the string of 'leg-' plus the
// index of the current element in the collection plus one:
this.className = this.className.replace(matchedClass[0], 'leg-' + (i + 1));
}
});
$('tr').each(function(i) {
var matchedClass = this.className.match(/\bleg-\d+\b/);
// if a match exists:
if (matchedClass) {
this.className = this.className.replace(matchedClass[0], 'leg-' + (i + 1));
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr class="leg-2323523">
<td>1</td>
</tr>
<tr class="leg-2323523">
<td>2</td>
</tr>
<tr class="leg-2323523">
<td>3</td>
</tr>
<tr class="leg-2323523">
<td>4</td>
</tr>
</tbody>
</table>
Using an id is somewhat easier, since we don't need to preserve pre-existing concurrent ids, as we do with classes:
// selects all <tr> elements, sets their `id` property
// using the anonymous function available within prop():
$('tr').prop('id', function (i) {
// i: the index amongst the collection of <tr> elements:
return 'leg-' + (i+1);
});
$('tr').prop('id', function (i) {
return 'leg-' + (i+1);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
<tr>
<td>4</td>
</tr>
</tbody>
</table>
If the index/row-number is simply to be available to JavaScript, then you could just as easily use the native rowIndex property available to all HTMLTableRowElements:
// selects <tr> elements, binds the 'mouseenter' event-handler:
$('tr').on('mouseenter', function() {
// logs the HTMLTableRowElement rowIndex property
// to the console:
console.log(this.rowIndex);
});
$('tr').on('mouseenter', function() {
console.log(this.rowIndex);
});
td {
border: 1px solid #000;
width: 4em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tbody>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
<tr>
<td>3</td>
</tr>
<tr>
<td>4</td>
</tr>
</tbody>
</table>
References:
JavaScript:
HTMLTableRowElement.
JavaScript Regular Expression Guide.
String.prototype.match().
String.prototype.replace().
jQuery:
each().
prop().
Updated
Based on your comment below and your updated question, here is an updated solution.
var removed = $(".leg-2"),
siblings = removed.nextAll(), // affect only next siblings to removed element
pos = ""; // store current number after "leg-"
removed.remove(); // remove element
siblings.each(function (k) {
$(this).removeClass(function (i, key) {
pos = key.split("-")[1]; // update number after "leg-"
return (key.match(/\bleg-\S+/g) || []).join(' ');
}).addClass("leg-" + (pos - 1)); // add "leg-" plus new position
});
See it working here.
You can use .removeClass() with .match() to remove class starts with leg and then add class leg plus tr's index using .addClass().
See it working here.
$("tr").each(function (k) {
k++;
$(this).removeClass(function (i, key) {
return (key.match(/\bleg-\S+/g) || []).join(' ');
}).addClass("leg-" + k);
});
Try this it will re-name the class:
$(document).ready(function(){
$("#click").click(function(){
reorder();
});
});
function reorder(){
$('#myTable > tbody > tr').each(function(index) {
console.log($(this).attr('class','leg-'+(index+1)));//avaoid starting fron 0
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="myTable">
<tr class="leg-1"><td>a1</td></tr>
<tr class="leg-2"><td>a2</td></tr>
<tr class="leg-3"><td>a3</td></tr>
<tr class="leg-7"><td>a4</td></tr><!--after click on button class will become class="leg-4" -->
<tr class="leg-8"><td>a5</td></tr><!--after click on button class will become class="leg-5" -->
</table>
<button id="click">CliCk</button>

Categories