I have an awkward problem, due to inheriting a shedload of really, really badly formatted HTML.
Basically I have some table rows like this:
<tr class="odd">...</tr>
<tr class="odd">...</tr>
<tr class="odd">...</tr>
<tr class="even">...</tr>
<tr class="even">...</tr>
<tr class="even">...</tr>
<tr class="odd">...</tr>
<tr class="odd">...</tr>
<tr class="odd">...</tr>
And what I need is a jQuery selector that will give me the first element of each block of classes. Is that clear enough? I'm not sure how else to explain it.
So in the example case I would want rows 1, 4, and 7.
Ive done this so far by selecting every nth child, but Ive now realised this wont work as there wont always be the same number of rows in each block of classes.
Any help you guys can give it appreciated, as always :)
Cheers!
You'll need to employ some strategic use of :not() and adjacent sibling selectors:
$('tr.odd:first-child, tr.even:first-child, tr:not(.odd) + tr.odd, tr:not(.even) + tr.even')
The tr:not(...) + tr... bits select any tr element that's directly preceded by a tr that does not have the same class name. You can't do this dynamically (e.g. with some sort of wildcard), but it's entirely possible if you specify each class name separately. This will ensure you only select the first element in each contiguous group.
The reason the :first-child pseudo is required is simply because + won't match the first child, since it implies a relationship between an element and its preceding sibling. Note that :first-child accounts for the very first tr only. You could replace tr.odd:first-child, tr.even:first-child with simply tr:first-child if every tr element will have exactly one of either class name, but I specify them anyway for clarity's sake.
Last but not least, this doubles as a valid CSS selector, so you can use it in a stylesheet as well if you like.
$('tr.odd:not(.odd+.odd),tr.even:not(.even+.even)')
This just takes any .odd element which isn't following another .odd, and any .even element which isn't following another .even element.
this may help you
$('button').click(function() {
var lastGroup = ''
$('.groups tr').each(function() {
if(lastGroup != this.className) {
$(this).css('background-color', 'red');
lastGroup = this.className;
}
});
});
explanation: loop through all the TR and verify if the class name (this.className) is equal to lastGroup. if not equal, we have a new group (first element of the group). if equal, ignore and continue. this will work with any class name used.
JSFiddle: http://jsfiddle.net/bq7zB/
Loop through and check if the current element matches the last one, otherwise it's the first of its set:
var lastClass = false;
$('tr.odd, tr.even').each({ function() {
lastClass = $(this).attr('class');
if($(this).attr('class') != lastClass){
// Do your conditional stuff here
}
}
var prevClass = '';
$('tr').each(function(){
var thisClass = $(this).attr('class');
if (prevClass === thisClass) {
//do nothing?
} else {
//push in array? do something to the row?
}
});
Related
I have a SQL-PHP printed table, and a select at the top of the table. The table contains contacts classified by towns.
At the beginning, the table shows all contacts. If I specify the town, I want to hide the rest.
I'm trying to use a jQuery script
<script>
function updateit(){
if ($("#table").filter("tr") === $("#selectTown").val()) $(this).show(););
else {$(this).hide();};
}
</script>
[...]
<select id="selectTown" onchange="updateit()"><option value="NY">New York</option><option value="TX">Texas</option></select>
<table id="table">
bla bla bla...
</table>
Before I tried with find() function, but with no success.
Any suggestions?
This line $("#table").filter("tr") === $("#selectTown").val() compares document elements to string, it would not work.
Simplest solution would be to do all elements hidden and than select and show all matching elements. Example:
$('tr').hide();
$('tr[value=' + $("#selectTown").val() + ']').show();
I'm not sure where you got the idea for this code, but filter() definitely doesn't do what you think it's doing. $("#table").filter("tr") is going to give you a list of tr elements in the table. That list itself isn't going to equal any selected value, it's just an array of elements.
Mocking up a few things in a jsFiddle here, perhaps you want something more like this:
$('#selectTown').change(function () {
$('#table tr').hide();
$('#table tr').filter(function () {
return $(this).find('td:first').text() === $('#selectTown').val();
}).show();
});
What this does is:
Bind to the change event of the select element (which is preferred over the inline binding you do in your markup, just in general).
Hide all of the tr elements first, you'll show the ones you want in a moment.
Show all of the tr elements which match the filter.
The filter in this case is a function which returns true if the text inside of the td element (you will likely need to update that selector) equals the selected value. The main difference here vs. what you tried is that .filter() is returning a list of matched (filtered) elements, not an actual value to compare. Internal to the filter is where the comparison takes place, in this case using a function (which needs to return true or false for any given element being filtered).
I am trying to compare if the two td elements are the same within 1 table.
I have
var element = $('.table td');
$('table:odd td','.table').each(function(){
if(element.is(this)){
console.log('find')
}
)}
I want to check if the element is the same as this but my codes don't seem to work here.
Can anyone give me a hint for it? Thanks a lot
regular DOM nodes can be compared against each other, and using get(0) will get you the first DOM node from the jQuery collection :
var element = $('.table td');
$('table:odd td','.table').each(function(){
if (element.get(0) === this ){
console.log('find');
}
});
It does look like element would contain more than one element, especially as you're iterating the same selector with an added :odd on the next line, so the comparison seems a little strange, and will probably return false ?
I'm trying to create a copy/paste system for a HTML table using jQuery and a context menu plugin and I'm trying to uniquely name all of the newly created rows. So I have a function that is cloning the selected row and inserting the new row above:
function cloneAbove(TR) {
var newRow = $(TR).clone();
var lastID = $(TR).attr('id');
var newID = Number(lastID.substring(3))-0.1;
//See if that row already exists:
if($('#tr_'+newID).length){
alert('#tr_'+newID+' Exists');
//If it does exist, we divide the newID by 10 until we find one that doesn't:
var i = 0;
while(i < 1){
newID = newID/10;
if($('#tr_'+newID).length > 0){
i = 1;
}
}
}
$(newRow).attr('id','tr_'+newID);
$(TR).before(newRow);
$(".target").contextmenu(option);
}
First it clones the selected row (ie: '#tr_1'), subtracts 0.1 for the new row's id (ie: '#tr_0.9'), then it is supposed to check to see if that id already exists - this is where my problem is - if it exists it enters a loop to divide by 10 until it finds a id that doesn't.
Here is a sample of the table:
<table id="table" border=1>
<tr class="target" id="tr_1" oncontextmenu="context('tr1')">
<td id="tr_1_1">Row1</td>
<td id="tr_1_2">Row1</td>
</tr>
<tr class="target" id="tr_2" oncontextmenu="context('tr2')">
<td id="tr_2_1">Row2</td>
<td id="tr_2_2">Row2</td>
</tr>
</table>
The .length works for the 'hard coded' elements as they exist when the page loads, but it won't detect any of the newly created elements. Any suggestions?
You're building "id" values that are going to confuse jQuery. The selector "#tr_0.9" means, "find the element with id 'tr_0' and class '9'", not "find the element with id 'tr_0.9'".
Setting aside the fact that that strikes me as a pretty weird way to construct "id" values, you may be able to make it work by "quoting" the "." characters:
if ($(('#tr_' + newId).replace(/\./g, "\\.")).length) {
// ... found a duplicate ...
What that does is substitute "." for "." in the constructed trial "id" value. You only want to do that, of course, when looking for the elements via a jQuery selector; you don't want the actual "id" value to have backslashes in it.
Alternatively, you could replace the "." characters with "_" or something.
You need to think about how your jQuery selector is getting parsed. When you add a new row your new row's id is set to a decimal digit (ie '0.9'). But when using the jQuery selector
$('#tr_0.9') you are saying:
get the an element with id of 'tr_0'
and a class of '9'.
The dot operator is the notation for a class selector. Try using whole number values instead of decimal ones.
Edit: I was too slow!
HTML
<tr id="rowId"><td><textarea class="inputTextarea"></textarea></td><td><textarea class="inputTextarea"></textarea></td></tr>
<tr id="rowId2"><td><textarea class="inputTextarea"></textarea></td><td><textarea class="inputTextarea"></textarea></td></tr>
<tr id="rowId3"><td><textarea class="inputTextarea"></textarea></td><td><textarea class="inputTextarea"></textarea></td></tr>
Provided I know rowId, how do I find the next textarea ON THIS PAGE, starting at any arbitary point. I don't mean ANY input, textarea only. I need to be able to start AT ANY row, and progress on to the next textarea, essentially going down the rows.
EDIT
Based on answers, I used the following code to traverse the textareas row by row:
var curElt = $('#' + startAt); //startAt is the first row id
for(var i=1; i < 10; i++) {
$(curElt).find('textarea').eq(0).val(i);
$(curElt).find('textarea').eq(1).val(i+1);
curElt = $(curElt).next();
}
You can use the next and find methods:
$('#' + current_row_id).next().find('textarea').eq(0);
next will get the next sibling, and then find will find all of the elements within the set that match the passed-in selector(s), then eq(0) will grab the first element in the resulting set returned from find.
$('#rowId2').find('textarea');
That will find both children of the row. If you want the first one, either:
$('#rowId2').find('textarea').eq(0); //jQuery object
$('#rowId2').find('textarea')[0]; //DOM Element
Edit: If you only know one row and want to find the first textarea in the next row:
$('#rowId').next().find('textarea').eq(0);
$textarea = $('#rowId textarea').eq(0);
$nextarea = $textarea.closest('tr').next().find('textarea').eq(0);
Just to clarify, $.fn.next() finds the next sibling in the DOM.
Starting from the textarea, first
you have to find its parent-tr (
$textarea.closest('tr') ).
From there, use next to find the next tr
( .next() )
Finally, find the first
textarea within that tr (
.find('textarea').eq(0) )
Try this:
$("#rowID textarea:first-child").val()
<tr>
<td>#</td>
<td>2009</td>
<td><a class="delete_this">Click</a></td>
</tr>
I want to use jquery and get the text of 2nd (second) "td" when clicking the anchor. I want the "td" in the same tr as the anchor...
How do I do this?
So far I have
$(document).ready(function(){
$(".delete_this').click(function(){
var myNUmber = $(this).parent()....///And this i should write the code to get the text for second td in tr where the anchor belongs to
})
})
Here's a few ways:
$(this).parent().siblings("td:eq(1)").text()
If your looking for the cell before you can do it this way:
$(this).parent().prev().text()
var myNUmber = $(this).parent().siblings().get(1).text();
Details are here
$('.delete_this').closest('tr').children(':eq(1)') .text();
1) Get the .delete_this A tag
2) Get the parent TR
3) Get the 2nd TD
4) Get the Text of the 2nd TD
Your better adding just 1 click event by using .live rather than adding multiple click handlers, if you had a large table this will impact performance (think 100 separate bound events).
Also remember to prefix class selectors with nodeName if you can (here you are sure all delete_this are anchors)
$('a.delete_this').live('click', function(){
var myNUmber = $(this).parent().siblings().get(1).text();
});