Click on table cells and handle class changes per cell - javascript

I have a table looking like this:
<table class="ui celled table unstackable" id="tblHits">
<thead>
<tr>
<th>40</th>
<th>40</th>
<th>40</th>
<th>25</th>
<th>15</th>
</tr>
</thead>
<tbody>
<tr>
<td class="addNone" id="t01">01</td>
<td class="addNone" id="t02">02</td>
<td class="addNone" id="t03">03</td>
<td class="addNone" id="t04">04</td>
<td class="addNone" id="t05">05</td>
</tr>
</tbody>
</table>
What I want to do is to click TD with ID=t01 to change that class from one to another. The classes are defined to only change background colors. I have added some code to actually be able to select one TD already, but for some reason, I'm not able to click TD with id=t03 after that. Nothing happens. Any ideas on how I can do that?
My script is this:
$("#tblHits:has(td)").click(function(e) {
var clickedCell= $(e.target).closest("td");
if ( $('#t'+ clickedCell.text() + '').hasClass( "addNone" )) {
$("#tblHits td").removeClass("addNone");
$('#t'+ clickedCell.text() + '').addClass("addHit");
alert('Clicked table cell value is: <b> ' + clickedCell.text());
}
else if ( $('#t'+ clickedCell.text() + '').hasClass( "addHit" )) {
$("#tblHits td").removeClass("addHit");
$('#t'+ clickedCell.text() + '').addClass("addMiss");
alert('Clicked table cell value is: <b> ' + clickedCell.text());
}
else if ( $('#t'+ clickedCell.text() + '').hasClass( "addMiss" )) {
$("#tblHits td").removeClass("addMiss");
$('#t'+ clickedCell.text() + '').addClass("addNone");
alert('Clicked table cell value is: <b> ' + clickedCell.text());
});
Thank you in advance for any feedback concerning this issue!

Try to use "event delegation" to listen to clicks on a higher element (you did this, listening to clicks on the table).
However, fetching the clicked cell doesn't seem to work as planned.
You could just check if the clicked element is the td you want, and work from there. This also gives a small performance boost, since you can exit the script if something is clicked that you are not interested about.
$('#tblHits').on('click', function (evt) {
var $td = $(evt.target);
if (!$td.is('td')) return;
if ($td.hasClass('addNone')) {
$td.removeClass('addNone').addClass('addHit');
} else
if ($td.hasClass('addHit')) {
$td.removeClass('addHit').addClass('addMiss');
} else
if ($td.hasClass('addMiss')) {
$td.removeClass('addMiss').addClass('addNone');
}
});
See this fiddle: https://jsfiddle.net/bkry0txr/4/
btw, I'd advice adding another selector to the td, eg. another classname.
For example:
<tr>
<td class="hitbox addNone"></td>
<td class="hitbox addHit"></td>
<!-- etc -->
</tr>
And then the JS:
$('#tblHits').on('click', function (evt) {
var $td = $(evt.target);
if (!$td.is('.hitbox')) return;
// etc..
});
This way you can have other td elements, or even change to other elements if you'd like. The JS doesn't need to change, as long as the element you want to check have the classname hitbox.

You can bind a click event on all your td, and for each one, you can change your css as you like!
There is no need to use this $('#t'+ clickedCell.text()).
$( "td" ).each(function(index) {
$(this).on("click", function(){
if ($(this).hasClass('addNone')) {
$(this).removeClass('addNone').addClass('addHit');
} else if ($(this).hasClass('addHit')) {
$(this).removeClass('addHit').addClass('addMiss');
} else if ($(this).hasClass('addMiss')) {
$(this).removeClass('addMiss').addClass('addNone');
}
});
});

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

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

Building an anchor menu automatically with jQuery

I need some help for doing a menu built automatically with jQuery.
I have the following HTML structure
<table width="99%" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td height="20">DescripciĆ³n</td>
</tr>
<tr>
<td height="20">Preguntas Frecuentes</td>
</tr>
<tr>
<td height="20">Incompatibilidades</td>
</tr>
</tbody>
</table>
...
<a name="descripcion"></a>
<h1>Descripcion</h1>
...
<a name="preguntas"></a>
<h1>Preguntas</h1>
In this case the anchor "incompatibilidades" doesn't exist, so what I need is to create a jQuery script which look for any "a" tag which has its corresponding link.
The result I expect is the following:
<table width="99%" border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td height="20">DescripciĆ³n</td>
</tr>
<tr>
<td height="20">Preguntas Frecuentes</td>
</tr>
</tbody>
</table>
I'll appreciate your help!
If I understood correctly, you could do something like this:
var menu = $("#menu");
$("a").each(function() {
var $this = $(this);
var name = $this.attr("name");
if (typeof(name) !== 'undefined') {
var links = $("a[href='#"+name+"']");
var link;
if (links) {
link = links.eq(0);
}
if (link && typeof(link) !== 'undefined') {
menu.append("<tr><td><a href='#"+name+"'>"+link.text()+"</a></td></tr>");
}
}
});
You have to add "menu" id in a new table to create what you expect.
If you would like to remove the the table row which contains the mentioned anchor tag which does not exist, you could use:
$(document).ready(function() {
$('a[href="#incompatibilidades"]').closest('tr').remove(); // Or detach, possibly
});
If you would like to add in an h1 + a and append it to your DOM, you could use:
$(document).ready(function() {
var anchor = $('<a></a>', { 'name' : 'incompatibilidades' });
var h1 = $('<h1></h1>', { text: 'incompatibilidades' });
// Append these to the DOM here.
});
First, you shouldn't be using named anchors, but ids instead (the "name attribute on the a element is obsolete1"), to give:
<h1 id="descripcion">Descripcion</h1>
...
<h1 id="preguntas">Preguntas</h1>
Also, using a <table> element to present a list is a little non-semantic, since it's non-tabular information; instead use an ordered list, <ol>. So, with that in mind, I'd suggest the following jQuery:
$('h1[id]').each(function() {
var target = this.id;
$('#toc').append(function() {
return '<li>' + target + '</li>';
});
});
#toc {
text-transform: capitalize;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol id="toc"></ol>
<h1 id="descripcion">Descripcion</h1>
...
<h1 id="preguntas">Preguntas</h1>
This approach is based on an assumption that you want to build a table of contents to link to those elements that are on the page.
Notes:
http://www.w3.org/TR/html-markup/a.html#a-constraints.
Without testing, and if I get your question correct - you are looking for something like this:
$().ready(function() {
// scan all links in your menu
$('table').find('a').each(function() {
// grep href attribute
var target = $(this).attr('href');
// element does not exist?
if(! $(target).length) {
// remove parent row
$(this).closest('tr').remove();
}
});
});
And - as #David Thomas mentioned correctly, you shouldn't be using named anchors, but ids instead - if you do so, you can use the anchor ('#xyz') directly as id selector as I did in the function above.

Collapsing table rows with multiple tbody elements

I have a table that looks like this:
<table>
<thead>
<tr><th>Customer</th><th>Order</th><th>Month</th></tr>
</thead>
<tbody>
<tr><td>Customer 1</td><td>#1</td><td>January</td></tr>
<tr><td>Customer 1</td><td>#2</td><td>April</td></tr>
<tr><td>Customer 1</td><td>#3</td><td>March</td></tr>
</tbody>
<tbody>
<tr><td>Customer 2</td><td>#1</td><td>January</td></tr>
<tr><td>Customer 2</td><td>#2</td><td>April</td></tr>
<tr><td>Customer 2</td><td>#3</td><td>March</td></tr>
</tbody>
<tbody>
<tr><td>Customer 3</td><td>#1</td><td>January</td></tr>
<tr><td>Customer 3</td><td>#2</td><td>April</td></tr>
<tr><td>Customer 3</td><td>#3</td><td>March</td></tr>
</tbody>
....
.... 10s of records like this
</table>
I want to make each tbody element clickable (collapsible) so that in a collapsed state, I would get a summary of what is inside (say, Customer 1 | 3 Entries) and in an expanded state, I would get to see the actual rows.
Can this be done for the table structured as shown above?
JSFiddle here: http://jsfiddle.net/Ju4xH/
It's a little messy and the animations don't work (I'm guessing it's because it's on the <tr>s, but here's what I came up with:
$(document).ready(function () {
$("table").on("click", "tbody", function () {
var $this = $(this);
var myTRs = $this.children("tr");
if ($this.hasClass("collapsed")) {
$this.removeClass("collapsed");
myTRs.first().remove();
myTRs.show();
} else {
$this.addClass("collapsed");
var newInfo = myTRs.first().children("td").first().text() + " | " + myTRs.length + " entries";
myTRs.hide();
$this.prepend($("<tr><td colspan='3'>" + newInfo + "</td></tr>").hide()).find("tr").first().slideDown();
}
});
});
DEMO: http://jsfiddle.net/ZhqAf/1/
When you click a non-collapsed <tbody>, it will hide the rows and prepend a new one with the details you wanted. When you click a collapsed <tbody>, it removes the new "details" row, and shows the original rows.
I have included header for each row by counting the number of rows in that tbody and after insert bind the click event on each header to show content of that tbody .
$(document).ready(function(){
$('table tbody').each(function(){
var num=$(this).children().length;
// alert(num);
$(this).before("<div id='header' class='header'>"+num +" entries </div>");
//alert($(this).html());
$(this).hide();
});
$('.header').on('click',function(){
$(this).next().slideToggle("slow");
});
});
JS FIDDLE LINK
EDITED
if you really want slide animation you can wrap all tbody also in a div . so slideToggel will give you animation also. You can use this as follows :
$(document).ready(function(){
$('table tbody').each(function(){
var num=$(this).children().length;
// alert(num);
$(this).before("<div id='header' class='header'>"+num +" entries </div>");
//alert($(this).html());
$(this).wrap('<div class="new" />');
$('.new').hide();
});
$('.header').on('click',function(){
$(this).next().slideToggle("slow");
$(this)
});
});
JS FIDDLE LINK FOR EDITED PART

Categories