Clone table and filter out rows - javascript

Hello I got a question regarding cloning a table.
I want to filter out some specific results and output those results.
Let me explain myself better with HTML code:
<table class="table table-striped" id="ProfileList2">
<tbody>
<tr>
<td>21</td>
<td>2014-02-28 21:12:12</td>
<td>20</td>
<td>one</td>
<td>166</td>
</tr>
<tr>
<td>22</td>
<td>2014-03-01 14:04:35</td>
<td>20</td>
<td>one</td>
<td>0</td>
</tr>
<tr>
<td>23</td>
<td>2014-03-03 15:22:56</td>
<td>20</td>
<td>one</td>
<td>21</td>
</tr>
<tr>
<td>24</td>
<td>2014-03-03 17:15:56</td>
<td>20</td>
<td>one</td>
<td>21</td>
</tr>
<tr>
<td>25</td>
<td>2014-03-03 17:50:49</td>
<td>20</td>
<td>one</td>
<td>0</td>
</tr>
<tr>
<td>26</td>
<td>2014-03-05 17:33:42</td>
<td>20</td>
<td>one</td>
<td>24</td>
</tr>
</tbody>
</table>
<p class="result"></p>
In my Javascript I want to filter out all the results that have within the last <td> or every <tr> the value 0.
var $mainTable = $("#ProfileList2");
var $training = $mainTable.clone("tr td:nth-child(5):not(:contains('0'))");
$('p').append($training);
This code will clone a direct copy without doing any filtering.
If I change the clone function to, for example: find function, it will only return the table-data: 166 21 21 24.
Is there any function available that will return the whole table-row instead of only the table-data?
JSFIDDLE OVER HERE

To grab the table rows, change this:
$mainTable.find("tr td:nth-child(5):not(:contains('0'))")
… to this:
$mainTable.find("tr td:nth-child(5):not(:contains('0'))").parent()
Also note that a paragraph element cannot contain a table element according to the specification. (Although most browsers allow it.) Changing it to a div would be better.
Fiddle 1
Also note that the contains selector will search for a 0 within the cell, so it will match cells containing "160" as well as those containing "0."
Instead, you could filter to exclude only cells that equal "0":
$mainTable
.find("tr td:nth-child(5)")
.filter(function() {return $(this).text() != '0';})
.parent();
Fiddle 2

Well, you could copy the whole thing and then filter out what you don't like, how about that?
var copy = $("#ProfileList2").clone();
$('p').append(copy);
copy.find("tr td:nth-child(5):contains('0')").parent().remove();
Make note that it is not a good idea to have multiple elements with the same id.

Related

Requesting text from a table row using jquery returns ''

I started using jQuery around a week ago and I wanted to make something like a search from an existing table.
When calling text() from any row it shows and empty string '' making it impossible to compare the searched string to the existing ones in the table.
For example, the following code returns 4 instances of ''. How can I fix this?
$(document).ready(() => {
$('#test tr').filter(() => {
console.log($(this).text());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<table>
<tbody id="test">
<tr>
<td>example</td>
<td>1</td>
</tr>
<tr>
<td>example</td>
<td>2</td>
</tr>
<tr>
<td>example</td>
<td>3</td>
</tr>
<tr>
<td>example</td>
<td>4</td>
</tr>
</tbody>
</table>
There's two problems in your code. Firstly you're using an arrow function so the this keyword will point to the outer context, not the tr element within the iteration. To fix this use an anonymous function, or receive the tr as the argument to the arrow function. I've done the latter in the example below.
The second issue is that you're using filter() as an iterator, which is not correct. filter() should be used to reduce a set of elements within a jQuery object. As you want to loop in this case, you should just use each() instead.
jQuery($ => {
$('#test tr').each((i, tr) => {
console.log($(tr).text().trim());
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<table>
<tbody id="test">
<tr>
<td>example</td>
<td>1</td>
</tr>
<tr>
<td>example</td>
<td>2</td>
</tr>
<tr>
<td>example</td>
<td>3</td>
</tr>
<tr>
<td>example</td>
<td>4</td>
</tr>
</tbody>
</table>

Changing Table's tr:even with a different background color

I know how to do this with jquery, by doing this:
$("#rateTable tr:even").css("background", "#e7edea");
However, the format I am using will not allow jquery. I tried the code below, but it is saying that the style is null. Does anyone see what I am doing wrong?
document.getElementById("rateTable tr:even").style.background = "#e7edea";
<table id="rateTable">
<tr>
<td>Blue</td>
<td>Green</td>
</tr>
<tr>
<td>Red</td>
<td>Purple</td>
</tr>
<tr>
<td>Teal</td>
<td>Yellow</td>
</tr>
</table>
You don't really need JavaScript for this. It could been done in plain CSS with the nth-child pseudo-class.
tr:nth-child(even) {
background: #E7EDEA;
}
<table id="rateTable">
<tr>
<td>Blue</td>
<td>Green</td>
</tr>
<tr>
<td>Red</td>
<td>Purple</td>
</tr>
<tr>
<td>Teal</td>
<td>Yellow</td>
</tr>
</table>
You can do it with #rateTable tr:nth-of-type(even) as your selector. document.selectElementById() only works when you give it the exact string being used as an id, not a CSS selector. I would do it with CSS because it will update automatically and is likely faster, but you can do it in JS if you want:
const evenRows = document.querySelectorAll("#rateTable tr:nth-of-type(even)")
for (const row of evenRows) row.style.background = "#e7edea"
<table id="rateTable">
<tr>
<td>Blue</td>
<td>Green</td>
</tr>
<tr>
<td>Red</td>
<td>Purple</td>
</tr>
<tr>
<td>Teal</td>
<td>Yellow</td>
</tr>
<tr>
<td>Orange</td>
<td>Pink</td>
</tr>
</table>
Try to use querySelectorAll and next iterate over received collection to change background. See below:
var trToChange = document.querySelectorAll("#rateTable tr:nth-child(even)");
for(var i = 0; i < trToChange.length; i++){
trToChange[i].style.background = "#e7edea";
}

How to remove TR if there is a specific text inside its TD's in jquery?

I want to remove the TR if its 2nd TD value is similar to another TRs TD value and it's last TD value shouldn't be HIT. And the another scenario is if I have 3 TRs with the same data then 2 of them should be removed and 1 should remain there.
Example:
<table>
<tr>
<td>ID</td>
<td>Ref No</td>
<td>Name</td>
<td>Result</td>
</tr>
<tr>
<td>1</td>
<td>1121</td>
<td>Joseph</td>
<td>CLEAR</td>
</tr>
<tr>
<td>2</td>
<td>1122</td>
<td>Mike</td>
<td>CLEAR</td>
</tr>
<tr>
<td>3</td>
<td>1122</td>
<td>Mike</td>
<td>CLEAR</td>
</tr>
<tr>
<td>4</td>
<td>1122</td>
<td>Mike</td>
<td>HIT</td>
</tr>
<tr>
<td>5</td>
<td>1123</td>
<td>Jim</td>
<td>HIT</td>
</tr>
<tr>
<td>6</td>
<td>1124</td>
<td>James</td>
<td>CLEAR</td>
</tr>
<tr>
<td>7</td>
<td>1124</td>
<td>James</td>
<td>CLEAR</td>
</tr>
<tr>
<td>8</td>
<td>1124</td>
<td>James</td>
<td>CLEAR</td>
</tr>
</table>
What I want:
<table>
<tr>
<td>ID</td>
<td>Ref No</td>
<td>Name</td>
<td>Result</td>
</tr>
<tr>
<td>1</td>
<td>1121</td>
<td>Joseph</td>
<td>CLEAR</td>
</tr>
<tr>
<td>4</td>
<td>1122</td>
<td>Mike</td>
<td>HIT</td>
</tr>
<tr>
<td>5</td>
<td>1123</td>
<td>Jim</td>
<td>HIT</td>
</tr>
<tr>
<td>6</td>
<td>1124</td>
<td>James</td>
<td>CLEAR</td>
</tr>
</table>
Can anybody tell me how to achieve this task?
Any help would be highly appreciated.
So i made this clumsy answer for you. You can check it out in the fiddle here.
EDIT: after some discussion about what should the behaviour be, i updated the fiddle. so now it adds the check if there are any fields in the duplicates that have a "HIT" value in fourth column it will keep the first row with HIT value, otherwise it will keep the first value for each unique second column value.
I am sure there is a better/simpler/more effective way to do this with jQuery, but that is what I came up with. The basic algorithm is this: get all rows and iterate. For each row: find the value in second td (column), check all subsequent rows, fetch the value in second column there and compare them. if they are the same, remove the duplicate row from DOM.
//get the table rows, this should be done with a different selector if there are more tables e.g. with class or id...
$tableRows = $("tr");
//iterate over all elements (rows)
$tableRows.each(function(index, element) {
var $element = $(element);
//get the value of the current element
var currentRowValue = $element.find("td:nth-child(2)").text();
//check all elements that come after the current element if the value matches, if so, remove the matching element
for (var i = index + 1; i < $tableRows.length; i++) {
var $rowToCompare = $($tableRows[i]);
var valueToCompare = $rowToCompare.find("td:nth-child(2)").text();
if(valueToCompare === currentRowValue) {
//remove the duplicate from dom
//if the second row (the duplicate) has 4th column of "HIT" then keep the second row and remove the first row
var duplicateRowFourthColumnVal = $rowToCompare.find("td:nth-child(4)").text();
if(duplicateRowFourthColumnVal == "HIT") {
$element.remove();
}
else {
$rowToCompare.remove();
}
}
}
});`

html table to json - modify cells

Well, I have following html table:
<table id="people" border="1">
<thead>
<tr>
<th>Name</th>
<th>Places</th>
<th>Grade</th>
</tr>
</thead>
<tbody>
<tr>
<td>Oscar</td>
<td>New York</td>
<td>16.5</td>
</tr>
<tr>
<td>Antonio</td>
<td>
<p>New York</p>
<p>Chicago</p>
<p>Toronto</p>
</td>
<td>14</td>
</tr>
<tr>
<td>Jessica</td>
<td>New York</td>
<td>19</td>
</tr>
</tbody>
Now when I use the jquery tableToJson function I get this output:
[
{"Name":"Oscar","Places":"New York","Grade":"16.5"},
{"Name":"Antonio","Places":"New York\n\t\t\tChicago\n\t\t\t\tToronto","Grade":"14"},
{"Name":"Jessica","Places":"New York","Grade":"19"}
]
Now look at Antonio, the function created
{"Name":"Antonio","Places":"New York\n\t\tChicago\n\t\t\t\tToronto","Grade":"14"}
But instead of
\n
I want places also to be displayed as a JSON array like this:
{"Name":"Antonio","Places":["New York","Chicago","Toronto"],"Grade":"14"}
I know there are options described here (https://github.com/lightswitch05/table-to-json), but I don't know which one to use, or how to use them, as it is not really documented, how to use them in detail.
Any help would be really appreciated :-)
If you want to update the existing array try using this
var places = [
{"Name":"Oscar","Places":"New York","Grade":"16.5"},
{"Name":"Antonio","Places":"New York\n Chicago\n Toronto","Grade":"14"},
{"Name":"Jessica","Places":"New York","Grade":"19"}
];
for(var x=0;x<places.length;x++){
places[x].Places = places[x].Places.split("\n");
}
console.log(places);

Calculate cell value based on formula and values in other cells

I have a table in a HTML file, and I want to calculate one cell's value based on other cells' values and a cell value as a formula. Take a look at this picture:
In my table, I have 1900 ratios and three factors in three columns. How I can calculate the result column values based on their respective formula column value?
Note: I use only *, /, +, and - in my formulas. Also, the table has an ID (ratiotable), but the <tr> and <td> don't have any ID or class names assigned to them.
If you know another webpage that did something like this, please let me see this.
Thank you very much.
Edit: The HTML code is like this. Note, I snipped a number of the rows. The actual number of rows is 1900:
<table>
<thead>
<tr>
<th>Ratio Name</th>
<th>Factor1</th>
<th>Factor2</th>
<th>Factor3</th>
<th>Formula</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name1</td>
<td>22</td>
<td>11</td>
<td></td>
<td>Factor1/Factor2</td>
<td></td>
</tr>
<tr>
<td>Name2</td>
<td>22</td>
<td>33</td>
<td>11</td>
<td>Factor1/Factor2*Factor3</td>
<td></td>
</tr>
<tr>
<td>Name1</td>
<td>12</td>
<td></td>
<td>4</td>
<td>(Factor1+Factor2)/Factor3</td>
<td></td>
</tr>
</tbody>
This was a really interesting challenge. I've put together a little JSFiddle here that does what you describe. It essentially replaces the string parts of the formula with their value counterparts, then evals the result. Hopefully this helps!
My Markup
<table>
<thead>
<tr>
<th>Ratio Name</th>
<th>Factor1</th>
<th>Factor2</th>
<th>Factor3</th>
<th>Formula</th>
<th>Result</th>
</tr>
</thead>
<tbody>
<tr>
<td>Name1</td>
<td>22</td>
<td>11</td>
<td></td>
<td>Factor1/Factor2</td>
<td></td>
</tr>
<tr>
<td>Name2</td>
<td>22</td>
<td>33</td>
<td>11</td>
<td>Factor1/Factor2*Factor3</td>
<td></td>
</tr>
<tr>
<td>Name1</td>
<td>12</td>
<td></td>
<td>4</td>
<td>(Factor1+Factor2)/Factor3</td>
<td></td>
</tr>
</tbody>
</table>
​
My JavaScript
$(function() {
$('tbody tr').each(function() {
var $this = $(this),
f1 = $this.find('td').eq(1).text() || 0,
f2 = $this.find('td').eq(2).text() || 0,
f3 = $this.find('td').eq(3).text() || 0,
formula = $this.find('td').eq(4).text(),
resultTd = $this.find('td').last();
formula = formula.replace('Factor1',f1)
.replace('Factor2',f2)
.replace('Factor3',f3);
resultTd.text(eval(formula));
});
});​
loop through all rows and use javascript eval() function
function cellValue(x,y){
return $('#ratiotable').find('tr:eq('+(y+1)+')>td:eq('+(x+1)+')').text();
}
function setCellValue(x,y,s){
$('#ratiotable').find('tr:eq('+(y+1)+')>td:eq('+(x+1)+')').text(s);
}
$(function(){
$.each($('#ratiotable tr'),function(i,tr){
var Factor1 = parseInt(cellValue(0,i));
var Factor2 = parseInt(cellValue(1,i));
var Factor3 = parseInt(cellValue(2,i));
var Formula = $.trim(cellValue(3,i));
var Result = eval(Formula);
setCellValue(4,i,Result);
});
});
like this

Categories