The user can provide an array of string and I want to look in a table and check the assosiated checkbox with the table row when one of the string is found.
I can see that the $("#activelisttable tr:contains(" + substr[i] + ")") contains a <tr> but it simply dosen't go in the .each function.
Here is the full code :
$("#savelistactive").click(function() {
var substr = $("#listtextactive").val().split("\n");
for (var i = 0; i < substr.length; i++)
{
$("#activelisttable tr:contains(" + substr[i] + ")").each(function(item) {
$(this).children("input").prop('checked', true);
});
}
$("#background").fadeOut("slow");
$("#listactive").fadeOut("slow");
});
Fiddle link : http://jsfiddle.net/5WVwe/
Problem Recap:
The problem is with your selector inside the for loop. #NobleMushtak recommended that you change the .each() in your original fiddle to be:
$("#activelisttable tr:contains(" + substr[i] + ")").children("input").prop('checked', true);
This was a good suggestion. However, having not seen your markup, it was unclear the exact HTML structure you were using. According to your fiddle, your HTML markup contains <tr>'s which then contain <th>'s within them:
<tr>
<th>
<input type="checkbox" class="selectall" />
</th>
<th>name</th>
</tr>
This means that there are no .children() of the <tr>'s with a type of input.
Solution:
Change .children() to be .find():
$("#activelisttable tr:contains(" + substr[i] + ")").find("input").prop('checked', true);
.find() does a deep search of all nested elements versus .children() which will only traverse down one more layer.
Works great with the change.
Updated JSFiddle
Reference Documentation:
.find()
.children()
Related
UPDATE: http://jsfiddle.net/daltontech/qfjr7e6a/ - Thanks to both that helped!
Original question:
I get JSON data from a report in my HelpDesk software that I import into an HTML table (via Python) & one of the columns is the address of the request, but it is not clickable. I can edit the Python file (though I don't expect the answer is there) and the HTML file (and Javascript is both fine and expected to be the solution), but I cannot change the JSON data (much).
I can use JQuery, but if vanilla Javascript can do it, that is my preference.
I tried innerHTML (with and without global flag), but after about 20 rows, it fails spectacularly in IE & Chrome (all I tested) & this list is typically 50+.
I do use innerHTML successfully in other places, mainly linking technician names to their requests (a shorter list) like:
{ document.body.innerHTML = document.body.innerHTML.replace('Jenny', 'Jenny'); }
Here's what I have to work with:
<table class="Requests" id="Requests">
<thead><tr><th>URL</th><th>Title</th><th>Technician</th></tr></thead>
<tr><td>https://helpdesk.domain.com/8675309</td><td>I need a phone number</td><td>Jenny</td></tr>
<tr><td>https://helpdesk.domain.com/8675310</td><td>Some other issue</td>
<td>John</td></tr>
</table>
Everything before the number is always the same, so that gives some flexibility and I can have the JSON file provide a few options (just not the <a> tag...) like:
1. 8675309
2. https://helpdesk.domain.com/8675309
3. sometext8675309
4. sometext8675309someothertext
I'm hoping to accomplish either of the two row examples - either works, might prefer latter:
<table class="Requests" id="Requests">
<thead><tr><th>URL</th><th>Title</th><th>Technician</th></tr></thead>
<tr><td>https://helpdesk.domain.com/8675309</td><td>I need a phone number</td><td>Jenny</td></tr>
<tr><td>link</td><td>Some other issue</td><td>John</td></tr>
</table>
Commented Code:
// get the elements
document
.querySelectorAll(".Requests > tbody > tr > td:first-child")
// for each element remove the text and
// replace it with an anchor tag
// use the original element's text as the link
.forEach(c => {
let a = Object.assign(document.createElement("a"), {
href: c.textContent,
textContent: c.textContent
});
c.textContent = "";
c.appendChild(a);
});
Example Snippet
document
.querySelectorAll(".Requests > tbody > tr > td:first-child")
.forEach(c =>
c.parentNode.replaceChild(Object.assign(document.createElement("a"), {
href: c.textContent,
textContent: c.textContent
}), c)
);
<table class="Requests" id="Requests">
<thead>
<tr>
<th>URL</th>
<th>Title</th>
<th>Technician</th>
</tr>
</thead>
<tr>
<td>https://helpdesk.domain.com/8675309</td>
<td>I need a phone number</td>
<td>Jenny</td>
</tr>
<tr>
<td>https://helpdesk.domain.com/8675310</td>
<td>Some other issue</td>
<td>John</td>
</tr>
</table>
If I understand your question right, you want to use client-side JS to modify an already generated HTML table.
The below code works for me with +200 rows so I don't think using .innerHTML has an inherent issue, maybe there is something else causing your code to crash?
EDIT (IE):
let rows = document.querySelectorAll('#Requests tr');
for (let i = 1; i < rows.length; i++) {
rows[i].getElementsByTagName('td')[0].innerHTML = '<a href="' + rows[i].getElementsByTagName('td')[0]
.innerHTML + '">' + rows[i].getElementsByTagName('td')[0].innerHTML + '</a>';
}
let rows = document.querySelectorAll('#Requests tr');
rows.forEach(function(r, i) {
if (i > 0) {
r.getElementsByTagName('td')[0].innerHTML = '' + r.getElementsByTagName('td')[0].innerHTML + ''
}
});
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/
What i'm trying to do is to get the cell of this where the classname is "revision_id".
<tr>
<td class="supplierOrderId">10790</td>
<td class="revision_id">#7</td>
<td class="supplier">DGI Developpement </td>
<td class="quantity">80</td>
<td class="stock">0</td>
<td class="purchase_price">10.00</td>
<td class="comments"> </td>
</tr>
I managed to do it this way :
revision = this.parentNode.parentNode;
revisionId = revision.cells[1].innerHTML.replace( /[^\d.]/g, '' );
(cause I wanna get the int of the string)
iRevisionId = parseInt(revisionId);
Is there a more proper way to do it, with the given className ?
Because in the case where someone adds a cell before mine in the future, my code is going to be "deprecated".
Hope i've given all the details,
Thanks by advance.
// More Details //
The problem with most answers is that they work only if I have 1 <tr>. Once I get multiple, it gets every revisionID like this :
console.log(result) -> #1#2#3#4
(if I have 4 <tr> for exemple)
So this is why I am getting the GOOD one like this :
revision = this.parentNode.parentNode; // outputs the good <tr>
but after that, I can't get the with the given className.
if this is tr
var data = $(this).children(".revision_id").text()
Using the text() method, you can get the text inside your td element.
After that just parse it like you did with parseInt()
$(function() {
var quantity = $('tr td.quantity').text();
console.log(parseInt(quantity));
});
you can do via jquery like this:
var value= parseInt($(".vision_id").text().match(/[0-9]+/g)[0]);
FIDDLE EXAMPLE
Depends on whether you can use jQuery or not.
Pure JavaScript
With pure JS, provided you're using a modern browser, you can use the getElementsByClassName function. For the purpose of this demonstration, I've assumed you have an ID on your table you can use.
var myClassName = 'revision_id';
var table = document.getElementById('mytable');
// the desired TD
var td = table.getElementsByClassName( myClassName ) );
See Mozilla's docs on getElementsByClassName.
Also, this answer works with backwards compatibility.
jQuery
Of course, this becomes easier with jQuery:
var $td = $('#mytable td.revision_id');
Demo here: http://jsfiddle.net/uJB2y/1/
Well if you want it with jquery then you can use .filter() method:
var text = $('td').filter(function () {
return this.className === 'revision_id';
}).text().slice(1);
text = +text; // conversion for int
alert(text);
Demo
I've been struggling with this issue for a while now. Maybe you can help.
I have a table with a checkbox at the beginning of each row. I defined a function which reloads the table at regular intervals. It uses jQuery's load() function on a JSP which generates the new table.
The problem is that I need to preserve the checkbox values until the user makes up his mind on which items to select. Currently, their values are lost between updates.
The current code I use that tries to fix it is:
refreshId = setInterval(function()
{
var allTicks = new Array();
$('#myTable input:checked').each(function() {
allTicks.push($(this).attr('id'));
});
$('#myTable').load('/get-table.jsp', null,
function (responseText,textStatus, req ){
$('#my-table').tablesorter();
//alert(allTicks + ' length ' + allTicks.length);
for (i = 0 ; i < allTicks.length; i++ )
$("#my-table input#" + allTicks[i]).attr('checked', true);
});
}, $refreshInterval);
The id of each checkbox is the same as the table entry next to it.
My idea was to store all the checked checkboxes' ids into an array before the update and to change their values after the update is done, as most of the entries will be preserved, and the ones that are new won't really matter.
'#myTable' is the div in which the table is loaded and '#my-table' is the id of the table which is generated. The checkbox inputs are generated along with the new table and with the same ids as before.
The weird thing is that applying tablesorter to the newly generated table works, but getting the elements with the stored ids doesn't.
Any solutions?
P.S: I know that this approach to table generation isn't really the best, but my JS skills were limited back then. I'd like to keep this solution for now and fix the problem.
EDIT:
Applied the syntax suggested by Didier G. and added some extra test blocks that check the status before and after the checkbox ticking.
Looks like this now:
refreshId = setInterval(function()
{
var allTicks = []
var $myTable = $('#my-table');
allTicks = $myTable.find('input:checked').map(function() { return this.id; });
$('#myTable').load('/get-table.jsp', null,
function (responseText,textStatus, req ){
$myTable = $('#my-table');
$('#my-table').tablesorter();
var msg = 'Before: \n';
$myTable.find('input').each(function(){
msg = msg + this.id + " " + $(this).prop('checked') + '\n';
});
//alert(msg);
//alert(allTicks + ' length ' + allTicks.length);
for (i = 0 ; i < allTicks.length; i++ ){
$myTable.find('#' + allTicks[i]).prop('checked', true);
}
msg = 'After: '
$myTable.find('input').each(function(){
msg = msg + this.id + " " + $(this).prop('checked') + '\n';
});
//alert(msg);
});
}, $refreshInterval);
If I uncomment the alert lines, and check 2 checkboxes, on the next update I get (for 3 row table):
Before: host2 false
host3 false
host4 false
object [Object] length 2
After: host2 false
host3 false
host4 false
Also did a previous check on the contents of the array and it has all the correct entries.
Can the DOM change or working with an entirely new table instance be a cause of this?
EDIT2:
Here's a sample of the table generated by the JSP (edited for confidentiality purposes):
<table id="my-table" class="tablesorter">
<thead>
<tr>
<th>Full Name</th>
<th>IP Address</th>
<th>Role</th>
<th>Job Slots</th>
<th>Status</th>
<th>Management</th>
</tr>
</thead>
<tbody>
<tr>
<td>head</td>
<td>10.20.1.14</td>
<td>H</td>
<td>4</td>
<td>ON</td>
<td>Permanent</td>
</tr>
<tr>
<td>
<input type="checkbox" id="host2" name="host2"/>
host2
</td>
<td>10.20.1.7</td>
<td>C</td>
<td>4</td>
<td>BSTART</td>
<td>Dynamic</td>
</tr>
<tr>
<td><input type="checkbox" id="host3" name="host3"/>
host3</td>
<td>10.20.1.9</td>
<td>C</td>
<td>4</td>
<td>BSTART</td>
<td>Dynamic</td>
</tr>
<tr>
<td><input type="checkbox" id="host4" name="host4"/>
host4</td>
<td>10.20.1.11</td>
<td>C</td>
<td>4</td>
<td>BSTART</td>
<td>Dynamic</td>
</tr>
</tbody>
</table>
Note that the id and name of the checkbox coincide with the host name. Also note that the first td does not have a checkbox. That's the expected behavior.
Changing 'special' attributes like disbaled or checked should be done like this:
$(...).attr('checked','checked');
or this way if you are using jQuery 1.6 or later:
$(...).prop('checked', true); // more reliable
See jQUery doc about .attr() and .prop()
Here's your piece of code modified with a few optimizations (check the comments):
refreshId = setInterval(function()
{
var allTicks = [],
$myTable = $('#myTable'); // select once and re-use
// .map() returns an array which is what you are after
// also never do this: $(this).attr('id').
// 'id' is a property available in javascript and
// in .map() (and in .each()), 'this' is the current DOMElement so simply do:
// this.id
allTicks = $myTable.find('input:checked').map(function() { return this.id; });
$myTable.load('/get-table.jsp', null, function (responseText,textStatus, req ) {
$myTable.tablesorter();
//alert(allTicks + ' length ' + allTicks.length);
for (i = 0 ; i < allTicks.length; i++ )
// avoid prefixing with tagname if you have the ID: input#theId
// #xxx is unique and jquery will use javascript getElementById which is super fast ;-)
$myTable.find('#' + allTicks[i]).prop('checked', true);
});
}, $refreshInterval);
Let us assume that the JavaScript does retrieve and set the checkboxes ticks.
Then there still is a problem with the asynchrone Ajax call.
First try it with a very large $refreshInterval.
Place the for-loop before the tablesorter call.
Do not setInterval, but setTimeout and schedule this for one single time.
Then in the load function schedule the next time.
This prevents overlapping calls which were a possible cause for the error.
But may stop refreshing, when the load is not called. (Not so important.)
After lots of painful hours of digging up every small detail, I realized that my problem was not how I coded the thing, nor was it stuff like unexpected DOM changes, but a simple detail I failed to see:
The id I was trying to assign to the checkbox contained a period (".") character.
This causes lots of problems for jQuery when trying to look up that sort of id, because a period as-is acts as a class descriptor. To avoid this, the period character must be escaped using 2 backslashes.
For example:
$("#my.id") // incorrect
$("#my\\.id") // correct
So then the fix in my case would be:
$myTable.find('#' + allTicks[i].replace(".", "\\.")).prop('checked', true);
... and it finally works.
Thanks everyone for all your helping hands!
How can I use jQuery to get a particular instance of a class(headerGrid) within a Div(products).
I need to be able to get an instance of the class 'headerGrid' classed span which says "Get this Text". The instance is represented as the value within swap2(). My code is as follows...
<table id="products">
...
<tr>
<td>
<a onclick="swap2(1);"><img src="images/products/thumbs/image.png"/></a>
</td>
<td valign="top" class="product-text">
<span class="headerGrid">Get this Text</span><br /><br />
text
</td>
</tr>
...
</table>
E.g. if onclick="swap2(5);" then I need to get the 5th instance of '.headerGrid'
EDIT
Further more I need to select the text("Get this Text") rather then the object itself. Other wise it returns object [object Object].
I also tried selecting with .innerHTML which returns undefined.
Use the eq() selector. Example:
$("#products span.headerGrid").eq(4) //Zero based index
With your function:
function swap2(n) {
//Zero based index, subtract 1
var theText = $("#products span.headerGrid").eq(n - 1).html();
...
}
Using the :nth-child selector:
$('#products span.headerGrid:nth-child(5)')
Use $("#products span.headerGrid:nth-child(5)"), which will return the 5th span with class headerGrid in your element with ID products.
Function swap could look like this:
function swap(n){
var element = $("#products span.headerGrid:nth-child(" + n + ")");
//Rest of code
}
Small notice: You've mentioned DIV(products) in your question, but your code shows table.