Odd DOM Problem with Firefox - javascript

I'm experiencing an odd problem when trying to navigate through a table's rows and cells in a while loop using javascript. I'm using Firefox 3.5.7 on Win7 with Firebug enabled.
I have this markup:
<table>
<tbody>
<tr id='firstRow'><td>a</td><td>b</td><td>c</td></tr>
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>a</td><td>b</td><td>c</td></tr>
</tbody>
</table>
And this javascript:
var row = document.getElementById('firstRow');
console.log(row); // Row call 1
while (row) {
console.log(row); // Row call 2
row = row.nextSibling;
}
The problem I'm having is that on the line commented "Row call 1", Firebug is outputting
<tr id='firstRow'>
as expected. However, in the while loop, Firebug is giving me
<tr id='firstRow'>
<TextNode textContent="\n">
It is giving me different output for the exact same row, even immediately after the while loop begins executing and nothing else touched the row. For subsequent rows, it of course does not have id='firstRow' as an attribute.
The bigger problem this is giving me is that if I'm in the while loop, and I want to access a particular cell of the current row using row.cells[0], Firebug will give me an error that row.cells is undefined.
I want to know if someone could shed some light on this situation I am experiencing.

Firefox is picking up the whitespace between your tr elements as an additional node. Simply add a test that the node is indeed a tr before doing anything with it:
var row = document.getElementById('firstRow');
console.log(row); // Row call 1
while (row) {
if(row.nodeName == "TR"){
console.log(row); // Row call 2
}
row = row.nextSibling;
}
Note that the text nodes have a nodeName of #text and that nodeName will always return the element name in all caps regardless of how you have it in your document.

The TextNode is correct, because you do have that after the </tr>.
A simple workaround is to skip those textnodes - by either counting or testing if
row.tagName == 'TR'

Use the tbody.rows collection. It's simpler:
var row = document.getElementById('firstRow');
console.log(row); // Row call 1
var tbody = row.parentNode;
var rows = tbody.rows;
for (var i=row.rowIndex+1; i<rows.length; i++) {
row = rows[i];
console.log(row); // Row call 2, 3 ...
}
For more info, see http://msdn.microsoft.com/en-us/library/ms537484%28VS.85%29.aspx
(or just google rowIndex)
EDIT: If the table also contains thead and/or tfoot then it might be more appropriate to use row.sectionRowIndex

Related

Remove Last Character in th using ajax

How to remove last character inside of table header using javascript/ajax?
Example table:
Product
Price X
First
1000
Second
2000
What I want to reach is remove the X on Price X column header with some button, I've use slice before but not working.
How I supposed to do?
try this function:
function noLastCharaceter(txt) {
return txt.substr(0, txt.length - 1);
}
If you are asking, how to use it, so if your table id is "tableId", try this:
var table = document.getElementById("tableId");
var headers = table.getElementsByTagName("TH"); // list of "th" elements
headers[1].innerHTML = noLastCharacter(headers[1].innerHTML); // replace content of second column
Here is a very similar script that demonstrates the use of a suitable selector and a simple .slice() operation on the .textContent of the <th> element (please note that String.prototype.substr() is deprecated).
const th=document.querySelector("#myTable th:last-child");
th.textContent=th.textContent.slice(0,-2)
<table id="myTable"><thead><tr><th>Product</th><th>Price X</th><tr></thead><tbody>
<tr><td>First</td><td>1000</td></tr>
<tr><td>Second</td><td>2000</td></tr>
</tbody></table>

Hide tr (table row) with text content

I'm trying to hide a table row with javascript and css.
I have to admit that I'm still a beginner, so it's likely that I'll ask some stupid questions.
I want to hide a table row that somewhere in a td contains the text 'banana'.
Hopefully someone can help me out, thanks!
I've tried different kinds of code I found on the internet, but can't get anything working. This is what I got so far.
if(document.getElementsByTagName('tr').contains('banana'))
{
document.getElementsByTagName('tr').style.display = 'none';
}
Problem you have is you seem to be thinking in terms of jQuery. JQuery does loops under the hood. Since you are not in jQuery world, you need to do the loops yourself over the collection.
Select the rows
loop over the rows
Read the text
Check if text as match
if it does, hide it
// select all the rows
const rows = document.querySelectorAll('tr');
// loop over the rows
rows.forEach( function (row) {
// get the text of the row
var text = row.textContent; // case insensitive use .toLowerCase()
// see if it is in the string
if (text.includes('banana')) {
// add class to hide the row
row.classList.add('hidden')
}
})
.hidden {
display: none;
}
<table>
<tbody>
<tr>
<td>apple</td><td>$1.00</td>
</tr>
<tr>
<td>pear</td><td>$1.00</td>
</tr>
<tr>
<td>banana</td><td>$1.00</td>
</tr>
<tr>
<td>strawberry</td><td>$1.00</td>
</tr>
</tbody>
<table>
How will this fail? When the text joins between cells there is no whitespace so you can make matches that are not there. Is you search for something that is partial sting in another word that can also be wrong.
Other option you have is instead of looping over the rows, you loop over the cells. And if there is a match in the td, you hide the parent.
Instead of getting tr element you can get all td element and perform the following:
var tdcollection = document.getElementsByTagName('td');
for (var i = 0; i < tdcollection.length; i++) {
if (tdcollection[i].innerText.indexOf("banana") >= 0) {
tdcollection[i].parentElement.style.display = 'none';
}
}
<table>
<tr><td>banana</td><td>test1</td></tr>
<tr><td>grape</td><td>test2</td></tr>
</table>

Tampermonkey, Chrome how to automatically insert rows into a table?

I've tried with a stupid way of inserting code for a new table, but not even that seems to work. What would be the proper way?
Here's what I tried to do:
var table = document.getElementsByClassName("test")
[0].getElementsByClassName("tableclass");
for (var i = 0, l = table.length; i < l; i++) {
var content = table[i];
let s = content.innerHTML;
s = s.replace(/table/g, 'table border="1"');
s = s.replace(/tr>[\s\S]*?<tr>[\s\S]*?<td>3/g, 'tr>\r\n<tr>\r\n<td>3');
content.innerHTML = s;
}
And a fiddle: https://jsfiddle.net/d10tk7nr/1/
Also, the reason my stupid way doesn't contain the whole table is because some of the cells where I want to eventually use this would contain random data and I don't know how to skip that.
If you want to create a new HTML-Element, every browser got you covered on that.
var tr = document.createElement('tr');
console.log(tr);
The browser console will show you exactly what you have created - a new HTML element that is not yet part of the DOM:
<tr></tr>
The same goes with the creation of some content for that table row:
var td1 = document.createElement('td'),
td2 = document.createElement('td');
td1.innerText = '5';
td2.innerText = '6';
console.log(td1, td2);
The result will be two td-elements:
<td>5</td> <td>6</td>
Now we have to glue these parts together. Browsers will also have you coverd on this:
tr.append(td1);
tr.append(td2);
console.log(tr);
The result is a complete table row:
<tr><td>5</td><td>6</td></tr>
All we have to do is append this row to your table:
var table = document.querySelector('.test table tbody');
table.append(tr);
The elements you have created are now part of the DOM - child elements of the body of your table to be excact.
Click here for a fiddle
Edit
If you want to insert the new row to a specific place, you have to find the element you that should be next to it and use insertBefore. This would change the the last piece of code to:
var targetTr = document.querySelector('.test table tr:nth-child(2)');
targetTr.parentNode.insertBefore(tr, targetTr);
If you want to choose where to put your new row within your javascript, you can use the childNodes property:
console.log(table.childNodes);
I'd use insertAdjacentHTML, like so:
table[i].insertAdjacentHTML('beforeend', '<tr><td>5</td><td>6</td></tr>');
Please see this fiddle: https://jsfiddle.net/52axLsfn/4/
Also demonstrates how to set the border. Note that this code targets all tables, so depending on your situation you may want to be more specific.

Jquery contenteditable for all cells not rows

I create a table by adding rows and columns with JS and Jquery.
This is my code:
function AddColumnToDataTable(){
$('#tableHeader').append("<th> Header </th>").attr("contenteditable", true);
// Add a new ColumnHeader and set the property "editable"
}
function AddRowToDataTable(){
var count = $('#tableHeader').find("th").length;
// Get the count of Columns in the table
var newRow = $('#tableBody').append("<tr></tr>");
// Add a new Row
for(var i = 0; i < count ; i++){
newRow.find('tr').last().append("<td> Content </td>").attr("contenteditable", true);
// Fill the cells with a default text and set the property "editable"
}
}
So my question is, how can I write the code, that each cell is editable? At the moment, when I click, the whole row goes editable? Each cell should have that property.
I found a code that could help:
//$('table th:nth-child(4)').attr("contenteditable", true)
This makes the 4th header/cell editable, but how can I use it, each new created header/cell is the nth-child?
The jQuery append function doesn't return the new [appended] element, rather it returns the element that was appended to, hence the error in your code. Regardless, it's easier just to set the attribute manually in the append string. So, change this line:
newRow.find('tr').last().append("<td> Content </td>").attr("contenteditable", true);
To this:
newRow.find('tr').last().append("<td contenteditable="true"> Content </td>")
That should do it
It worked with
$('table td').last().attr("contenteditable", true);

Jquery Mobile Table Reflow

I'm trying to create my own script for a mobile version of my tables on my website.
Im currently using the script below to get the size of the table, and create new tables for each row, duplicating the headers into each new table.... (see: http://api.jquerymobile.com/table-reflow/ ) to get an idea of what I'm trying to achieve.
My script is as follows, but their is a js fiddle included at the bottom for a better example.
My problem is that I am only able to create 1 inside each table, where it should really be 3 rows, inside of each table. Again check the fiddle below for a proper example. Can anyone see why it is only creating 1 row in the table?
<script>
$(document).ready(function(){
var TableSize = $("table thead tr th").not("table.mobile_table thead tr th").size(); // Get # of columns
var i = 1;
var TableRowCount = $("table tbody tr").size(); // Get # of body rows
$("table thead tr th").each(function(){
$(this).attr("id", i++); // Give headers incrementing ID
});
for ( var CreateTables = 1; CreateTables < TableRowCount; CreateTables++ ){ // Create new table class="mobile_table" for each row
$("table").after("<table class='mobile_table'></table>");
}
$("table.mobile_table").each(function(){// Insert original headers into each row of new table as first column
var h = 1;
while ( ++h < TableSize){ // this is where the error is, it gives me the stuff below but x3 (the number of created tables)......
$("table.mobile_table").after("<tr><td></td><td></td><td></td></tr>");
}
});
console.log(TableSize);
console.log(TableRowCount);
});
</script>
See the fiddle: http://jsfiddle.net/Yf7KV/
Do you mean like this: http://jsfiddle.net/Yf7KV/2/
JS
$(this).append("<tr><td class='mobile_col_1'>Col 1</td><td class='mobile_col_2'>Col 2</td></tr>");
Explanation: Append will alllow you to append elements one after the another. html replaces with what you currently have

Categories

Resources