What is wrong with my dynamic append td in jquery/javascript? - javascript

I have a table where each row contains two elements:
<table>
<tr><td>A</td><td>B</td></tr>
<tr><td>C</td></tr>
</table>
I am trying to append a cell with "D" into the last row (the 2nd row that is already there in the current table), but am having difficulty.
I tried to perform:
$("table").children().get(1).append("<td>D</td>");
and
var elem = $("<td/>", {
text: 'D'
});
$("table").children().get(1).appendChild(elem);
and I get the error:
Uncaught Error: NotFoundError: DOM Exception 8
Putting tbody in there does not work either:
$("table tbody").children().get(1).appendChild(elem);
What is to proper way to do this?
I do not want to depend on just the "last td" as assuming I had another element "E", I would want it to automatically add to a third row by itself as opposed to tacking it on as a third column at the end of the 2nd row.

Try:
$("table td:last").after("<td>D</td>");
jsFiddle example
Results in the structure:
<table>
<tbody><tr><td>A</td><td>B</td></tr>
<tr><td>C</td><td>D</td></tr>
</tbody></table>

you can append dynamically by finding next letter from existed letter.May be You need to modify as per your requirement.
HTML
<table>
<tr>
<td>A</td>
<td>B</td>
</tr>
<tr>
<td>C</td>
</tr>
</table><button type="button" id="addanother" >Add</button>
JS :
$('#addanother').on('click',function(){
var length=$('table').find('td:last').parent().children().length;
var text=$('table').find('td:last').text();
var nextlet=nextLetter(text);
if(length == 2){
$('table').find('tr:last').after('<tr><td>'+nextlet+'</td></tr>');
}else if(length == 1){
$('table').find('td:last').after('<td>'+nextlet+'</td>');
}
});
// To get alphabets from A-Z from a-z
function nextLetter(s){
return s.replace(/([a-zA-Z])[^a-zA-Z]*$/, function(a){
var c= a.charCodeAt(0);
switch(c){
case 90: return 'A';
case 122: return 'a';
default: return String.fromCharCode(++c);
}
});
}
Fiddler : http://jsfiddle.net/j98H7/1/

try this:
$('<td>D</td>').appendTo('table tr:eq(1)');

Related

Remove all <tr> If does not contain "test" in text

I am making a chrome extension for the first time and need a little help with my Javascript.
In my popup menu I want a few buttons. Once someone presses this button lets say button "test". I want it to remove every single <tr> whom does not contain the word "test".
I am making this because the filter functionality on this website I use a lot is very slow. This way I can filter faster myself by removing the rows instead of the program searching through all of them.
This is what I have so far:
var searchString = 'TEST';
$("#tbody tr td:contains('" + searchString + "')").each(function Tester() {
if ($(this).text() != searchString) {
$(this).parent().remove();
}
});
<p>Remove all rows which don't contain:</p>
<button onclick="Tester()">TEST</button>
Firstly don't use inline JS. It's bad practice. Attach event handlers using unobtrusive JS instead.
To fix your actual issue, use the :contains selector along remove(), something like this:
$('button').click(function() {
var searchString = $(this).text();
$("#tbody tr td:contains('" + searchString + "')").closest('tr').remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Remove all rows which don't contain:</p>
<button>TEST</button>
<table>
<tbody id="tbody">
<tr>
<td>TEST</td>
</tr>
<tr>
<td>Foo</td>
</tr>
<tr>
<td>TEST</td>
</tr>
<tr>
<td>Bar</td>
</tr>
</tbody>
</table>
Try this
$("#tbody tr td").each( function () {
if ( $(this).text().indexOf( searchString ) == -1 ) { //notice the use of indexOf
$(this).parent().remove();//
}
});
Or you can check the row's text itself
$("#tbody tr").each( function () {
if ( $(this).text().indexOf( searchString ) == -1 ) {
$(this).remove();//
}
});

Finding last occurrence of text

I have the following type of table in html, which is generated dynamically by php :
<tr><td>Kiss the Girls</td><td>2016-01-01</td></tr>
<tr><td>Kiss the Girls</td><td>2016-02-05</td></tr>
<tr><td>Along Came a Spider</td><td>2016-01-07</td></tr>
<tr><td>Along Came a Spider</td><td>2016-01-22</td></tr>
<tr><td>Along Came a Spider</td><td>2016-03-31</td></tr>
I would like to be able to have a dynamic display filter that would allow the user to click a box and hide all but the latest version of the manuscript. So it might look like :
<tr><td>Kiss the Girls</td><td>2016-02-05</td></tr>
<tr><td>Along Came a Spider</td><td>2016-03-31</td></tr>
At this point none of the <tr> or <td> tags have an id or a class, but I could easily add a class to the first column (e.g., <td class='bookTitle'>). There is only one table on the page and php sorts it by date already. I'm open to jQuery or native JavaScript, though I would think this would be easier with jQuery. Seems like it could be done by just grabbing the last row before it changes names, but I'm not sure how to do that. Any thoughts?
According to 'Seems like it could be done by just grabbing the last row before it changes names', this is what I've come out with:
var rows = $("table tr");
if(rows.length > 0){
var last = $(rows[0]).find('td')[0].innerText;
for(var i=1; i<rows.length; i++){
var row = $(rows[i]);
var text = row.find('td')[0].innerText;
if(text === last){
$(rows[i-1]).hide();
}
last = text;
}
}
See the Pen Finding last occurrence of text by Tan Li Hau (#tanhauhau) on CodePen.
Iterate over the tr and store in key value pair where key as td content and value as object, after get the objects from it.
var a = {}; // object for storing dom element object
$('table tr').each(function() {
a[$('td:first', this).text().trim()] = this; // update the dom element object based on the column
});
var $res = $($.map(a, function(v) {
return v; // get objects and convert to jQuery object
}));
console.log($res);
$res.css('color', 'red');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr>
<td>Kiss the Girls</td>
<td>2016-01-01</td>
</tr>
<tr>
<td>Kiss the Girls</td>
<td>2016-02-05</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-07</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-22</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-03-31</td>
</tr>
</table>
FYI : If you want to maintain the order then the value with index and object array and set order based on that
You could iterate in reverse and remove everything you've seen before as you go:
function filterPreviousVersions ( ) {
var seen = {};
$( $('tr').get( ).reverse( ) ).each( function ( ) {
var text = $( 'td', this ).first( ).text();
if ( seen[ text ] )
$( this ).remove();
seen[ text ] = true;
} );
}
filterPreviousVersions();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr>
<td>Kiss the Girls</td>
<td>2016-01-01</td>
</tr>
<tr>
<td>Kiss the Girls</td>
<td>2016-02-05</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-07</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-01-22</td>
</tr>
<tr>
<td>Along Came a Spider</td>
<td>2016-03-31</td>
</tr>
</table>
If you add ids in increasing order as you add the rows,
You may use this :
var valArray = [];
$('.maindiv').each(function() {
valArray.push(parseInt($(this).attr('id'), 10));
})
valArray.sort(function(a, b) {
return a - b
})
alert("Last row : " + document.getElementById(valArray[valArray.length - 1]).innerHTML); // highest`
alert("Second last : " + document.getElementById(valArray[valArray.length - 2]).innerHTML);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="2" class="maindiv">Contents in row 2</div>
<div id="5" class="maindiv">Contents in row 5</div>
<div id="3" class="maindiv">Contents in row 3</div>
<div id="1" class="maindiv">Contents in row 1</div>
<div class="main">Contents in test row</div>
<div id="4" class="maindiv">Contents in row 4</div>
To put it all together:
Succint: (May have some performance impact for large tables with many duplicate values)
$('tr').each(function(){
$("tr :contains('" + $('td', this).first().html() + "')").last()
.parent().css('color', 'red');
});
Explanation for the succint version:-
$('tr').each(function(){ // for each row of the table
$("tr // find a child inside a tr
:contains('" // that contains the text
+ $('td', this) // present within a td of the row (in line 1)
.first().html() // at the beginning
+ "')") // Using string concat to pass variable to `contains` selector)
.last() // at the end (last occurence of text)
.parent() // invoke `parent()` to select whole row
.css('color', 'red'); // apply css to identify the desired row.
});
Verbose: (Using Set of ECMAScript6 or $.unique() to remove duplicates from the full list of names. This way, when the forEach loop at the end of the code runs, it'll iterate only one per name.)
var uniqueNames = [];
$('tr').each(function(){
uniqueNames.push($('td', this).first().html());
}); // this will return the list of names from the table
// Remove duplicates from the list of names
uniqueNames = new Set(uniqueNames); // OR: uniqueNames = $.unique(uniqueNames);
uniqueNames.forEach(function(el){
$("tr :contains('" + el + "')").last().parent().css('color', 'red');
});

DataTables issue: VM9075 dataTables.min.js:24Uncaught TypeError: Cannot set property '_DT_CellIndex' of undefined

I just started using DataTables and everything works fine when creating the table.
When I display 5, 24, 47 rows in my table, DataTables behaves as I would expect.
But I have this table that has around 700 rows and I get the error in Google Chrome,
"VM9075 dataTables.min.js:24Uncaught TypeError: Cannot set property '_DT_CellIndex' of undefined "
and in IE 9,
"SCRIPT5007: Unable to set value of the property '_DT_CellIndex': object is null or undefined
jquery-1.10.2.min.js, line 4 character 2367"
I don't have jQuery included twice btw.
I'm not sure how to proceed from here.
I tried to use the unminified version of the .js file to debug it more myself but i kept getting an "ext" method or property is undefined and couldn't fix that either.
Any help is appreciated!
I figured it out
The biggest issue was not knowing exactly what this error actually meant.
In my case it meant "the number of every <td> element in your table that is a child of a <tr> element doesn't match the number of <th> elements that are a child of the <thead> element."
My table was being generated by the server, and some of the <tr> elements had 27 <td> children (which was filling the whole width of the table up, but some of the <tr> elements only had 3, 4, or 5, ... <td> child elements which isn't a valid table.
I solved it by adding empty <td> elements in my table for the <tr> elements that lacked the correct number of <td> elements
var makeTableValidObject = {
thisWasCalled: 0,
makeTableValid: function() {
var tableToWorkOn = document.getElementById("table1");
//check the number of columns in the <thead> tag
//thead //tr //th elements
var numberOfColumnsInHeadTag = tableToWorkOn.children[1].children[0].children.length;
var numberOf_trElementsToValidate = tableToWorkOn.children[2].children.length;
//now go through each <tr> in the <tbody> and see if they all match the length of the thead columns
//tbody //all trs//all tds elements
//tableToWorkOn.children[2].children.children);
for(var i = 0; i < numberOf_trElementsToValidate; i++) {
//row my row make sure the columns have the correct number of elements
var tdColumnArray = tableToWorkOn.children[2].children[i].children
var trElementToAppendToIfNeeded = tableToWorkOn.children[2].children[i];
if(tdColumnArray.length != numberOfColumnsInHeadTag) {
//since they don't match up, make them valid
if(tdColumnArray.length < numberOfColumnsInHeadTag) {
//add the necessary number of blank <td> tags to the <tr> element to make this <tr> valid
var tdColumnArrayLength = tdColumnArray.length;
for(var j = 0; j < (numberOfColumnsInHeadTag - tdColumnArrayLength); j++) {
var blank_tdElement = document.createElement("td");
blank_tdElement.id = "validating_tdId" + i + "_" + j;
trElementToAppendToIfNeeded.appendChild(blank_tdElement);
}
}
else {
//TODO: remove <td> tags to make this <tr> valid if necessary
}
}
}
}
};
Edit 1:
It has been awhile and this question is still getting a bunch of views. I have since updated the code.
I replaced the first line of code with the second line to be more general
var numberOfColumnsInHeadTag = tableToWorkOn.children[1].children[0].children.length;
var numberOfColumnsInHeadTag = tableToWorkOn.querySelectorAll('thead')[0].querySelectorAll('th');
Pretty much where ever in the prior code you see the children.children I replaced that with the querySelectorAll(...) Function.
It uses css selectors which makes it amazingly powerful.
stay blessed
Ran into this same issue and implemented this same solution (essentially) in jquery based on Coty's. Hope this helps someone. :)
$( '.table' ).each(function( i ) {
var worktable = $(this);
var num_head_columns = worktable.find('thead tr th').length;
var rows_to_validate = worktable.find('tbody tr');
rows_to_validate.each( function (i) {
var row_columns = $(this).find('td').length;
for (i = $(this).find('td').length; i < num_head_columns; i++) {
$(this).append('<td class="hidden"></td>');
}
});
});
As answered by Coty, the problem lies in the mismatch of td elements generated in the header and body of table.
I'd like to highlight one of the reasons why it can occur (For .Net Users).
If Page numbers are being displayed at the end of gridview, they can disrupt table structure.
Remove AllowPaging="true" from your gridview to solve this.
And no worries because Datatable handles Paging.
you always keep four column but sometimes you will receive or append null td or only one td, td count always match with total column so when you does not have record then make td as following.
<th>No</th>
<th>Name</th>
<th>place</th>
<th>Price</th>
----------------------------------------
<td colspan="4">Data not found.</td>
<td style="display: none;"></td>
<td style="display: none;"></td>
<td style="display: none;"></td>
this error can also be triggered if you try to set options for the responsive extension for more columns than you have.
$( '.table' ).each(function( i ) {
var worktable = $(this);
var num_head_columns = worktable.find('thead tr th').length;
var rows_to_validate = worktable.find('tbody tr');
rows_to_validate.each( function (i) {
var row_columns = $(this).find('td').length;
for (i = $(this).find('td').length; i < num_head_columns; i++) {
$(this).append('<td class="hidden"></td>');
}
});
});

Check if variable exists in a html table with javascript

I have two tables at the moment. What Im looking to achieve is to select a row in one table, obtain the "filename" field from that and then check if that filename exists in the other table. If the file exists in both tables I want to change the colour of my progress tracker. Right now I have the selecting of the row working, but I can't seem to check it against the other table. Any help would be greatly appreciated.
HTML:
<table id="table">
<tr>
<td>--</td>
<td>Filename</td>
</tr>
<tr>
<td>1</td>
<td>Example1</td>
</tr>
<tr>
<td>2</td>
<td>Example2</td>
</tr>
</table>
<table id="table2">
<tr>
<td>--</td>
<td>Filename</td>
</tr>
<tr>
<td>1</td>
<td>Example1</td>
</tr>
</table>
<div id="words">
</div>
JavaScript:
$("#table").find("tr").click(function(){
$(this).addClass('selected').siblings().removeClass('selected');
var value=$(this).find('td:nth-child(2)').html();
//alert(value);
document.getElementById("words").innerHTML = value;
});
Thanks again for the help!
$("#table").on('click','tr',function(){ // <-- #1
var $this = $(this), // <-- #2
filename = $this.find('td:nth-child(2)').text(), // <-- #3
$words = $('#words');
$this.addClass('selected').siblings().removeClass('selected');
$words.html(filename).css('color','black');
if ( valueInTable('table2', 1, filename ) ){ // <-- #4
$words.css('color', 'blue');
}
});
function valueInTable(tableID, columnNum, searchString){
var found = false;
$( '#' + tableID + ' tr td:nth-child(' + columnNum + ')' ).each(function(){
if ($(this).text() == searchString ){
found = true;
return false;
}
});
return found;
}
This is important, this binds the event to the table. When a click occurs somewhere inside the table it checks the event registry, in this case, it checks to see if a TR was clicked. This is both a performance gain, since you're not creating an event for each row of the table, but also if you create new rows dynamically, you don't have to create a new event when you do. You create this event once and it's in place for all new/old rows of the table
Cache $(this) into a variable. You use it more than once and chances are you'll use it even more. You should not create a new jQuery object every time you want to refer to $(this), so stick it in a variable and reuse that
While .html() may work for you, if you have other embedded HTML, you might get values you were not intending (e.g., <span>filename</span>), for that reason, you only need .text(), which will just give you the text value and strip off all the nested HTML (leaving you with only filename)
Using a function comes with a penalty, but it's good to put long-logic elsewhere, in case you're doing anything more involved. For instance, your table could expand in width (number of columns) and you might also want to search them for a value, or you might have more tables you want to look in; this same function can be used for both of those cases.
as noted, the :contains() selector was built for what you're after However, there is one caveat. The problem with contains is that it lacks customization. If you want to modify your comparison to be a RegEx, or if you want to perform other manipulation using trim or truncate, you can't do that with contains. You could easily modify the code below to do: $.trim( $(this).text() ) == $.trim( searchString )
As #Pete commented, you can use if ($('#table2 td:contains(' + value + ')').length) as follows
$("#table").find("tr").click(function(){
$(this).addClass('selected').siblings().removeClass('selected');
var value=$(this).find('td:nth-child(2)').html();
//alert(value);
if ($('#table2 td:contains(' + value + ')').length) {
document.getElementById("words").innerHTML = value;
} else {
document.getElementById("words").innerHTML = "false";
}
});
See the JSFiddle for working example: https://jsfiddle.net/v14L4bqr/

jQuery Real Time Search - Remove Table Header Too

I am using the regular expression search code at this link, to allow real time search through a rather large table being populated server-side via php.
With a slight twist to the scenario describe in the above link, I am using table header tags to group (label) chunks of table row's together. I am preventing these table header row's from disappearing with the rest of the table row's so that when searching, the results are still nested in their group.
I would like the table header row's to disappear too, but only when there are no table row's between it and the next table header row. I'm not sure if counting row's will work, since the row's aren't gone, they're just hidden.
As an example, this is how my table is laid out:
HTML:
<table>
<tr>
<th colspan="2">Group 1</th>
</tr>
<tr class="searchable">
<td>Record 1</td>
<td>Record 2</td>
</tr>
<tr class="searchable">
<th>Group 2</th>
</tr>
<tr>
<td>Record 3</td>
<td>Record 4</td>
</tr>
</table>
jQuery:
$( document ).ready(function() {
var $rows = $('tr.searchable');
$('#search').keyup(function(e) {
if (e.keyCode == 27) { $(this).val("") }
var val = '^(?=.*\\b' + $.trim($(this).val()).split(/\s+/).join('\\b)(?=.*\\b') + ').*$',
reg = RegExp(val, 'i'),
text;
$rows.show().filter(function() {
text = $(this).text().replace(/\s+/g, ' ');
return !reg.test(text);
}).hide();
});
});
All help is appreciated!! Thanks!
I solved my dilemma by adding another class (unique to each group/label) and within the '.keyup()' section counting the ':visible' rows of each class. Once the number of rows in each class dropped below a specified number, I used '.hide()' in an if statement to make the table headers disappear. The else side of the if statement used '.show()' to bring the table headers back if their classes count rose above the specified number.
I also encountered this issue, it was solved by just targetting the body part for the .filter instead of the table as a whole.
$("#SearchPermissions").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#contentPart tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
Mind the $("#contentPart tr") part of the code.. this refers to the
This way the header is excluded from the search, thus will still be displayed while filtering table data

Categories