Replace specific table values using a Greasemonkey script - javascript

This is the first table on the page by the way. I want to be able to change the value of the td elements by referencing their position.
So, if I could state the 3rd td element in a specific table>tr pathway that would be great. And then to replace the text value. The text itself repeats a lot so I can't do a search for specific text values.
Also some of the td values are blank <td> </td>. And I would like to replace the blank table values as well. The tr class names are identical.
<table><tbody>
<tr class="table-header"><td colspan="4"><h3>First</h3></td></tr>
<tr class="table-header">
<th class="col">Number</th>
<th class="col">Name</th>
<th class="col">Quantity</th>
<th class="col">Type</th>
</tr>
<tr class="left-bottom-border">
<td>element 1</td>
<td>element3</td>
<td>element2</td>
<td>element3</td>
</tr>
<tr class="left-bottom-border">
<td>blah</td>
<td>blah</td>
<td>blah</td>
<td>blah</td>
</tr>
<tr class="left-bottom-border">
<td>stuff</td>
<td>stuff</td>
<td>stuff</td>
<td>blank</td>
</tr>
<tr class="left-bottom-border">
<td>I don't</td>
<td>think this matters</td>
<td>but I'm going to replace</td>
<td>all of the data</td>
</tr>
<tr class="table-header"><td colspan="4"><h3>Second Table</h3></td></tr>
<tr class="table-header">
<th class="col">Number</th>
<th class="col">Name</th>
<th class="col">Quantity</th>
<th class="col">Type</th>
</tr>
<tr class="left-bottom-border">
<td>More</td>
<td>x</td>
<td>x</td>
<td>x</td>
</tr>
<tr class="left-bottom-border">
<td>x</td>
<td>x</td>
<td>x</td>
<td>x</td>
</tr>
<tr class="table-header"><td colspan="4"><h3>Third Table</h3></td></tr>
<tr class="table-header">
<th class="col">Number</th>
<th class="col">Name</th>
<th class="col">Quantity</th>
<th class="col">Type</th>
</tr>
<tr class="left-bottom-border">
<td>element 1</td>
<td>element3</td>
<td>element2</td>
<td>element3</td>
</tr>
<tr class="left-bottom-border">
<td>so more elements</td>
<td>yada</td>
<td>yada</td>
<td>ya</td>
</tr>
<tr class="left-bottom-border">
<td>x</td>
<td>y</td>
<td>z</td>
<td>aa</td>
</tr>
</tbody></table>

Use document.querySelector()Doc to get the table, then use the .rowsDoc and .cellsDoc properties to get a particular <td> (or <th>) cell.
For example, for the code shown in the question, this will change the third row, first column ("element 1"):
var fstTable = document.querySelector ("body > table:nth-of-type(1)");
fstTable.rows[2].cells[0].textContent = "*changed*";
You can see this code in action at jsFiddle.
To find and replace blank cells, you could use the :empty selector with querySelectorAll -- except that this works poorly in practice due to stray whitespace.
The more robust alternative is to actually check the content of the cells. Like so:
var fstTable = document.querySelector ("body > table:nth-of-type(1)");
/*-- This only works when there is no stray whitespace:
var emptyCells = fstTable.querySelectorAll ("td:empty");
*/
var emptyCells = fstTable.querySelectorAll ("td");
for (var J = emptyCells.length - 1; J >= 0; --J) {
if (emptyCells[J].textContent.trim () == "") {
emptyCells[J].textContent = "*was blank*";
}
}
.trim() removes leading and trailing whitespace.

this javascript code let's you replace the content of a TD by it's index where 0 is the first element.
var tbl=document.getElementsByTagName("table")[0]; //get the first TABLE
var trs=tbl.getElementsByTagName('tr'); //get all TR's in that table
var replaceTD=function(TRindex,TDindex,value){
trs[TRindex].getElementsByTagName('td')[TDindex].innerHTML=value; // replaced with innerText
};
to change the second TD of the first TR that is not a title (so the third)
your indexes will be TRindex=2 cause it starts from 0 ...
and the TDindex=1
and the function you will call is :
replaceTD(2,1,'WHATEVER');

Related

Get the value of the next table cell onclick javascript

I am trying to get the value of the cell right of the cell where i click.
But right now I get the value of the cell I want, but I can click any cell in that row and get the desired value. But it should only be possible with the first column. So I click the any cell in the first column and I wanna get it's next neighbour cell value.
document.querySelector("#tableEventListId").addEventListener("click",event => {
let dataTr = event.target.parentNode;
let deleteEventId = dataTr.querySelectorAll("td")[1].innerText;
console.log(deleteEventId);
alert(deleteEventId);
Any help?
You can use nextElementSibling
document.getElementById('table1').onclick = function(event){
//REM: Target
var tElement = event.target;
if(
//REM: Only cells (=<td>)
tElement.tagName === 'TD' &&
//REM: Only first column cells
tElement.parentNode.firstElementChild === tElement
){
//REM: Next Elementsibling of Target or Null
var tNext = tElement.nextElementSibling;
if(tNext){
console.log('TD: ', tElement.textContent);
console.log('Next: ', tElement.nextElementSibling.textContent)
}
}
}
table, td{
border: 1px solid black
}
<table id = 'table1'>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr>
<td>A1</td>
<td>B1</td>
<td>C1</td>
</tr>
<tr>
<td>A2</td>
<td>B2</td>
<td>C2</td>
</tr>
<tr>
<td>A3</td>
<td>B3</td>
<td>C3</td>
</tr>
</tbody>
</table>
There is no HTML, so I can assume it's something like
<table border="1">
<tr>
<td class="first-column">1.1 (click here)</td>
<td>1.2</td>
<td>1.3</td>
</tr>
<tr>
<td class="first-column">2.1 (click here)</td>
<td>2.2</td>
<td>2.3</td>
</tr>
</table>
According to this HTML, you can try
const firstColumns = document.querySelectorAll(".first-column");
for (let i = 0; i < firstColumns.length; i++) {
firstColumns[i].addEventListener("click", function(event) {
let dataTr = event.target.parentNode;
let deleteEventId = dataTr.querySelectorAll("td")[1].innerText;
console.log(deleteEventId);
alert(deleteEventId);
});
}
Have a look https://jsfiddle.net/vyspiansky/k2toLd8w/
I would recommend you to a an event on every td element of the table. Then use nextElementSibling to get a next cell.
Look code snippet to see the example.
const cells = document.querySelectorAll('#tableEventListId td');
cells.forEach(cell => cell.onclick = function(){
const nextCell = cell.nextElementSibling;
if (nextCell)
alert(nextCell.innerHTML);
})
<table id="tableEventListId">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>11</td>
<td>22</td>
<td>33</td>
<td>44</td>
</tr>
<tr>
<td>111</td>
<td>222</td>
<td>333</td>
<td>444</td>
</tr>
<tr>
<td>1111</td>
<td>2222</td>
<td>3333</td>
<td>4444</td>
</tr>
</table>
If you want it to work only for cells at first column change the selector to #tableEventListId td:first-child.

Show value in textarea if checkbox is true

I have a table with four columns Name, Age, Country and a checkbox. If the checkbox is clicked(true) the name value of the row is showed in a textarea.
I am not really sure how I can realise that.
A row:
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
if the checkbox is true the value "James" should be shown in a textarea.
Thank you all.
I believe you need to do this for multiple rows in a table.
First select all the checkboxes with Document.querySelectorAll() to attach the event (click) to all the checkboxes.
The Document method querySelectorAll() returns a static (not live) NodeList representing a list of the document's elements that match the specified group of selectors.
Inside the event (click) handler function target all the checked checkboxes to loop through them to get the relevant names using Array.prototype.map():
The map() method creates a new array populated with the results of calling a provided function on every element in the calling array.
Also it is not good practice to mix up th and td inside of the same tr element. You should place th inside of a thead and td inside of tbody element:
var cb = document.querySelectorAll('input[type=checkbox]');
cb.forEach(function(ck){
ck.addEventListener('click', function(el){
var checked = document.querySelectorAll(':checked');
var tArea = document.getElementById('myText');
tArea.value = Array.from(checked).map(c => c.closest('tr').querySelector('td:nth-child(2)').textContent);
//or using spread syntax
//tArea.value = [...checked].map(c => c.closest('tr').querySelector('td:nth-child(2)').textContent);
});
});
table, th, td {
border: 1px solid black;
}
<table>
<thead>
<tr>
<th>Sl</th>
<th>Name</th>
<th>No</th>
<th>Country</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td scope="row">1</td>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<td scope="row">2</td>
<td>John</td>
<td>15</td>
<td>Germany</td>
<td><input type="checkbox"></td>
</tr>
</tbody>
</table>
<textarea id="myText"></textarea>
Try this:
[...document.querySelectorAll("input[type='checkbox']")].forEach(function (v){
v.addEventListener("change", function(){
document.querySelector("textarea").value = (this).checked ? (this).parentElement.parentElement.querySelector("td").innerHTML:'';
})});
<table>
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
<tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
</table>
<textarea></textarea>
Few javascript lines would be ok for you need.
let input = document.querySelector('input');
input.addEventListener('change', e=> {
if(e.target.checked == true){
// retreive tags
let name = document.querySelector('.name');
let textarea = document.querySelector('.textarea');
// insert data
textarea.innerText += name.innerText
}
})
<table>
<tr>
<th scope="row">1</th>
<td class="name">James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr>
</table>
<textarea class="textarea"></textarea>
Since your table can have multiple rows, where each can have the checkbox set or not, the textarea could get zero, one or more names.
So you would need to listen the change event, and then iterate the rows to collect the names, to finally set the value of the textarea:
let textarea = document.querySelector("textarea");
let table = document.querySelector("table");
table.addEventListener("change", function (e) {
let names = [];
for (let row of table.rows) {
if (row.querySelector("input[type=checkbox]").checked) {
names.push( row.children[1].textContent);
}
}
textarea.value = names.join("\n");
});
<table><tr>
<th scope="row">1</th>
<td>James</td>
<td>13</td>
<td>France</td>
<td><input type="checkbox"></td>
</tr><tr>
<th scope="row">2</th>
<td>Lucy</td>
<td>14</td>
<td>Germany</td>
<td><input type="checkbox"></td>
</tr></table>
<textarea></textarea>

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();
}
}
}
});`

For each element in class, console.log its value

For each element with the class the_name, I want to alert the value inside that element. So for the code below, it should alert three times. Once each for: "apples", "pears", and "plums".
Not sure what I am missing here.
var arr = $('.the_name');
for(var i = 0; i < arr.length; i++){
alert(arr[i].val());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<table id="datatable">
<thead>
<tr>
<th></th>
<th>Fruits</th>
</tr>
</thead>
<tbody>
<tr>
<td class="the_name">Apples</td>
<td class="the_count">3</td>
</tr>
<tr>
<td class="the_name">Pears</td>
<td class="the_count">2</td>
</tr>
<tr>
<td class="the_name">Plums</td>
<td class="the_count">5</td>
</tr>
<tr>
<td>Bananas</td>
<td>1</td>
</tr>
<tr>
<td>Oranges</td>
<td>2</td>
</tr>
</tbody>
</table>
By accessing the jQuery object by index you're retrieving the underlying DOMElement, not the jQuery object, and they do not have a val() method. Also note that you seems to be looking to retrieve the text of the element, not the value. As such, you should use each() to loop over the selected elements, using this to refer to the element of the current iteration. Try this:
$('.the_name').each(function() {
alert($(this).text());
});
Also note that for debugging purposes, console.log() should be used instead of alert().
$('.the_name').each(function() {
alert($(this).text());
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<table id="datatable">
<thead>
<tr>
<th></th>
<th>Fruits</th>
</tr>
</thead>
<tbody>
<tr>
<td class="the_name">Apples</td>
<td class="the_count">3</td>
</tr>
<tr>
<td class="the_name">Pears</td>
<td class="the_count">2</td>
</tr>
<tr>
<td class="the_name">Plums</td>
<td class="the_count">5</td>
</tr>
<tr>
<td>Bananas</td>
<td>1</td>
</tr>
<tr>
<td>Oranges</td>
<td>2</td>
</tr>
</tbody>
</table>
you need to use .text() instead of .val().
.val() works on input elements (or any element with a value attribute?) and .text() will not work on input elements. .val() gets the value of the input element -- regardless of type. .text() gets the innerText (not HTML) of all the matched elements:
.text()
The result is a string that contains
the combined text contents of all
matched elements. This method works on
both HTML and XML documents. Cannot be
used on input elements. For input
field text use the val attribute.
.val()
Get the content of the value attribute
of the first matched element
you need to use use $ to use jquery method .text().
var arr = $('.the_name');
for(var i = 0; i < arr.length; i++){
alert($(arr[i]).text());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<table id="datatable">
<thead>
<tr>
<th></th>
<th>Fruits</th>
</tr>
</thead>
<tbody>
<tr>
<td class="the_name">Apples</td>
<td class="the_count">3</td>
</tr>
<tr>
<td class="the_name">Pears</td>
<td class="the_count">2</td>
</tr>
<tr>
<td class="the_name">Plums</td>
<td class="the_count">5</td>
</tr>
<tr>
<td>Bananas</td>
<td>1</td>
</tr>
<tr>
<td>Oranges</td>
<td>2</td>
</tr>
</tbody>
</table>
The indexed values of a jQuery object are HTML elements, not jQuery objects.
You have to wrap them in a jQuery object before you can call jQuery methods on them:
var arr = $('.the_name');
for(var i = 0; i < arr.length; i++){
var html_element = arr[i];
var $html_element = $(html_element);
alert($html_element.val());
}

match words that appear at the beginning of the line in a table cell

Please take a look at this FIDDLE. How would you make sure it only matches the occurrence of Sodium that appear at the beginning of the line in a table cell, for example :
<td>Sodium</td>, <td>Sodium (from Kitchen Salt)</td>
but not
<td>Vitamin sodium</td>,<td>Fish Sodium</td>
My attempt
`var find_Sodium = /^Sodium/
alert($('.'+title+'table').find('td:contains(find_Sodium)').next().html());`
isn't working.
$.ajax({
url: "url.json",
success: function (data) {
$(data.query.results.json.json).each(function (index, item) {
var title = item.title;
var table = item.table;
if (table.indexOf("Sodium") >= 0) {
$('.'+ title+'table').html(''+table+'');
var find_Sodium = /^Sodium/;
alert($('.'+title+'table').find('td:contains(find_Sodium)').next().html());
}
});
},
error: function () {}
});
Table Structure:
<table class="tablesorter">
<thead>
<tr>
<td>Ingredient</td>
<td>Amount</td>
<td>% Daily Value**</td>
</tr>
</thead>
<tbody>
<tr>
<td>Calories</td>
<td>10</td>
<td></td>
</tr>
<tr>
<td>Sodium</td>
<td>2g</td>
<td><1</td>
</tr>
<tr>
<td>Vitamin C</td>
<td>110mg</td>
<td>4</td>
</tr>
<tr>
<td>Potassium sodium</td>
<td>235mg</td>
<td>6</td>
</tr>
<tr>
<td>Omega 6</td>
<td>1100mg</td>
<td>*</td>
</tr>
<tr>
<td>Vitamin Sodium</td>
<td>1200mg</td>
<td>*</td>
</tr>
<tr>
<td>Vitamin E</td>
<td>300mg</td>
<td>*</td>
</tr>
</tbody>
</table>
:contains does not accept a regex, the way to do this is to filter()
$('.'+title+'table').find('td').filter(function() {
return $(this).text().indexOf('Sodium') === 0;
}).next().html();
FIDDLE
using indexOf === 0 makes sure Sodium has an index of zero, being the first thing to occur in the elements text

Categories