Collapsing table rows with multiple tbody elements - javascript

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

Related

Click on table cells and handle class changes per cell

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');
}
});
});

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

Highlight some rows of my table in javascript

I need to highlight some rows of my table. This highlight is based on the rows present in my response object. This object can be as follow:
<table id="ListRequests" class="table table-striped">
<tbody>
<tr id="13955">
<td>JEAN DUPONT</td>
<td>ACLIMEX SPRL</td>
</tr>
</tbody>
</table>
Here is my javascript code:
var id = $("tbody tr", response).attr('id');
var cols = $('#' + id + ' td');
cols.effect("highlight", {}, 30000);
This works fine only if my response object contains only 1 row. Now I need to be able to highlight more than 1 rows at a time. So for example with the response object below:
<table id="ListRequests" class="table table-striped">
<tbody>
<tr id="13955">
<td>JEAN DUPONT</td>
<td>ACLIMEX SPRL</td>
</tr>
<tr id="13954">
<td>MIKE GIVER</td>
<td>ARGO INTERNATIONAL CORP</td>
</tr>
</tbody>
</table>
Any idea how to adapt my javascript code for that purpose ?
If you really want to do it the way you are doing it, than you need to use each
var trs = $("tbody tr", response);
trs.each( function () {
var id = this.id,
cols = $('#' + id + ' td');
cols.effect("highlight", {}, 30000);
});
Better off returning a JSON object with ids to select.
attr returns a single value, regardless how many elements are matched by the proceeding selector.
If you want to map every selected element to an ID and return array, you need map:
var ids = $("tbody tr", response).map(function (i, e) { return $(e).attr('id'); });
Once you have your list of IDs, you can iterate over that list, and highlight the matching rows in the DOM:
ids.forEach(function (id) {
var cols = $('#' + id + ' td');
cols.effect("highlight", {}, 30000);
});
Here is a working snippet.
The idea is to scrap the ids from the response you get by looping the tr nodes, from these ids build a css selector for the nodes you are interested in, and finally highlight all them.
function highlight(response){
// retrieve the ids from the response
var ids = $(response).find("tbody tr").map(function(){
// `this` will be the trs one after the other.
// `map` will put all returned values in an array.
return this.getAttribute("id");
}).get();
// build the css selector
var selector = "#" + ids.join(",#");
// highlight the corresponding nodes
$(selector).effect("highlight", {}, 30000);
}
// Call highlight with your response example.
highlight('<table id="ListRequests" class="table table-striped"><tbody><tr id="13955"><td>JEAN DUPONT</td><td>ACLIMEX SPRL</td></tr><tr id="13954"><td>MIKE GIVER</td><td>ARGO INTERNATIONAL CORP</td></tr></tbody></table>');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.min.js"></script>
<table id="ListRequests" class="table table-striped">
<tbody>
<tr id="13955">
<td>JEAN DUPONT</td>
<td>ACLIMEX SPRL</td>
</tr>
<tr id="13954">
<td>MIKE GIVER</td>
<td>ARGO INTERNATIONAL CORP</td>
</tr>
<tr id="1211">
<td>OTHER ONE</td>
<td>MUSN'T BE HIGHLIGHTED</td>
</tr>
</tbody>
</table>

Open link when doubleclicking on table row with jQuery

I have a table that looks like this:
<table id="table">
<thead>
<tr class='tablehead'>
<th>Test</th>
</tr>
</thead>
<tbody>
<tr class='tablecell'>
<td>
</td>
</tr>
</tbody>
</table>
I want to be able to double click on a row and then trigger a link.
An ID has to be transmitted somehow. Where should I define this? This allows me to edit the selected row afterwards.
Any idea how to do this?
Do you have any jQuery you've written yet? Here's a headstart...
Define your ID in the row:
<tr id="something">...</tr>
Then use something like this:
$('tr').dblclick(function(){
var id = $(this).attr('id');
//do something with id
})
This may help you:
jQuery(function($) {
$('#table tr').click(function() {
return false;
}).dblclick(function() {
window.location = url;
return false;
});
});
Do you mean something like this:
$(document).ready(function() {
$('.tablecell').click(function() {
return false;
}).dblclick(function() {
window.open("your_url");
return false;
});
});
and you could create a hidden field and populate that field with the id when double clicked.
Working demo: http://jsfiddle.net/Xr7LC/ (created from the sample code you provided)
Use dblclick api http://api.jquery.com/dblclick/
You can use $(this).attr('id') to get the id, and obviously you will define the id in a tag.
jQuery code for dblclick:
$(document).ready(function() {
$('#table >thead > tr').dblclick(function() {
alert('Row dblclicked');
alert($(this).attr('class'));
});
});​

jQuery remove elements after creation

I'm building a jQuery sortable list where the user can add items from a table, drag and sort and/or remove them. I can add and sort no problem, but I can't work out how to remove an item element after it has been added. I'm relatively new to js / jQuery, so I have a feeling there's something new to learn here about how it works!
I'll leave out the ui.sortable stuff here as I'm only concerned with removing items..
<table>
<tr>
<td><a class="addrelease" href="#" cat_id="1">add</a></td>
<td>Item 1</td>
</tr>
<tr>
<td><a class="addrelease" href="#" cat_id="2">add</a></td>
<td>Item 2</td>
</tr>
</table>
<div id="list"></div>
<script>
$("a.addrelease").click(function (e) {
e.preventDefault();
cat_id = $(this).attr('cat_id');
remove_str = " remove";
str = cat_id + remove_str;
$(str).appendTo("#list").hide().fadeIn();
});
$("a.remove").click(function (e) {
alert("This function doesn't seem to be called");
$(this).parent().remove(); //Doesn't happen..
});
</script>
I'm guessing that javascript doesn't recognize the new generated items - but I'm not sure, so I'm not sure where to start fixing it
Cheers
You should use live function to attach events to dynamically added elements.
Try this to bind click event to a.remove elements:
$("a.remove").live("click", function (e) {
alert("This function doesn't seem to be called");
$(this).parent().remove(); //Doesn't happen..
});
You're absolutely right, javascript won't recognise new items.
jQuery selectors will normally only match against elements currently in the document. When you use $("a.remove").function(), jQuery builds a list of nodes matching "a.remove", then calls function() on each of them.
The .live() function is special, and doesn't attach events directly to elements - instead, events bubbling up to the top of the DOM are evaluated to see if they match the selector.
IMHO, the best approach is to bind the remove handler when you create the new list entry:
str = cat_id + remove_str;
var remove = $(str);
remove.appendTo("#list").hide().fadeIn();
remove.click(function(e) { .... })
Disclaimer: Typed late at night & not tested!
Here is my answer of how I think you should modify your code:
http://jsfiddle.net/RY5CP/
<table>
<tr>
<td><a class="addrelease" href="#" rel="1">add</a></td>
<td>Item 1</td>
</tr>
<tr>
<td><a class="addrelease" href="#" rel="2">add</a></td>
<td>Item 2</td>
</tr>
</table>
<div id="list"></div>
<script type="text/javascript">
$("a.addrelease").click(function(e) {
e.preventDefault();
var catId = $(this).attr('rel');
var itemName = $(this).closest('td').next('td').text();
var newItem = '<p>' + catId + ' ' + itemName + ' remove';
$(newItem).appendTo('#list').hide().fadeIn();
});
$("a.remove").live('click', function(e) {
$(this).parent('p').remove();
});
</script>
It's not valid to use cat_1, cat_2 as HTML attributes. You can use the rel attribute if you need to have a specific value to be associated to your items
Use the live() method to have the click event handler automatically attached to items dynamically created

Categories