Trying to get the first cell in a row by using first-child or nth-child, but the syntax isn't playing nice. This is what I'm trying and it isn't working:
....
sections[key][2][sections[key][2].length-1] //Table Row
$(sections[key][2][sections[key][2].length-1]+":first-child") //Should be first cell of row
....
Instead it returns the entire document...
Your selector:
$(sections[key][2][sections[key][2].length-1]+":first-child")
is attempting to concatenate a JavaScript object with a string, which will result in (something similar) [object HTMLTableRowElement]:first-child which, obviously, is not going to produce a jQuery object, or a DOM node.
Given that (you say) $(sections[key][2][sections[key][2].length-1] is the tr element (though why you're using that notation within a jQuery selector is a mystery to me), I'd suggest:
$(sections[key][2][sections[key][2].length-1]).find('td:first-child');
JS Fiddle demo.
Note the use of the td with the :first-child pseudo-class, in order to prevent selecting the first-child of all subsequent elements.
However, to get the first cell of all table-rows (using jQuery's more understandable notation) I'd suggest:
$('table tr td:first-child')
JS Fiddle demo.
Or, to use :nth-child() to get an arbitrarily-numbered td:
$('table tr td:nth-child(2)')
JS Fiddle demo.
Should be:
$(sections[key][2][sections[key][2].length-1]+" td:first-child")
If you just want to return the first child regardless, why don't you do:
sections[key][2][sections[key][2].length-1].firstChild
Do keep in mind that selecting via jQuery what you can get very easily via DOM is just slowing down your code for no good reason.
Related
I realize the question title is a bit confusing, but in reality, I mean to ask exactly what I've typed.
I am trying to write a CSS file for printing (nausea rising) and I am wanting to eliminate white space in unnecessary rows (the necessity, or rather, the lack thereof, is determined by input fields that have empty values).
The proper CSS syntax (if there exists any) is relentlessly eluding me.
I have used selectors like this before:
input[type=text]
So I could assume (hopefully... gulp!) that I could use something like:
input[val='']
However:
1) I'm not sure using apostrophes/quotes is even legal inside those brackets (what's that area of a CSS selector called, again?)
2) I wouldn't know how to put a selector inside those brackets (if even possible) since the actual "tr"s are what I'm trying to target, just "tr"s with td children with input children with empty vals.
Wallowing in random syntax, I tried:
tr[td input val=]
Very much NOT to my surprise, did I find that obviously this didn't work, then I realized I had no clue how to proceed, if I wanted to accomplish this strictly in CSS.
~ Takes a quick breathe
Okay, I realize I'm asking a lot out of CSS, but if it's selector system wasn't so powerful I wouldn't even assume this possible.
Lastly, I am already implementing javascript, jQuery, and even server-side C#.net (WebMatrix) so if this answer is best solved using these other languages, I don't mind, I just want the simplest cleanest solution, if possible, as any scripting method I use will require the addition of another class to all td elements therein, and there are many, not to mention the scripting itself.
Any help, as always, is greatly appreciated.
---------------------EDIT REGARDING ALNITAK'S ANSWER------------------------
I tried to add the following jQuery just before my window.print(); JavaScript command:
$('tr > td > input[value=""]').parent().parent().css('display', 'none');
$('tr > td > input[value=""]').parent().parent().css('visibility', 'hidden');
I have checked my # of parents, and all is as it should be there. The only other thing that might be interfering is that I have razor embedded in the values by default (although they are explicitly assigned empty strings on page start so, it should be fine). Just in case though I also tried:
$('tr > td > input[value=null]').parent().parent().css('display', 'none');
$('tr > td > input[value=null]').parent().parent().css('visibility', 'hidden');
But, alas, to no avail.
You can't do this with pure selectors, because the end result of a selector is always the matching child node, not their ancestors.
You need to find those matching child nodes, and then climb back up the tree again, e.g. in jQuery:
$('tr > td > input[value=""]').parent().parent().css('color', 'red');
You can use .closest('tr') instead of .parent().parent() if you prefer.
Also using jQuery, you can use the .has() function to create a chain that matches elements containing particular children:
$('tr').has('> td > input[value=""]').css('color', 'red');
The .has() function is more efficient than using the :has pseudo-selector, although I would expect neither to be as efficient as the full selector above which takes advantage of document.querySelectorAll on modern browsers.
If you can't get the input[value=""] part to work, try this:
$('tr > td > input').filter(function() {
return this.value == '';
})....
If I'm understanding you correctly :
You can't do what you want to in CSS, not yet anyway.
What you're looking for is a css parent selector.
http://css-tricks.com/parent-selectors-in-css/
By using the selector:
tr td input[value='']
You'll be selecting the inputs, not the <tr>s.
One way to achieve what you want is to have something "watch" the page you're on (from javascript) and apply a class to anything you want hidden, when you print. Then in your print stylesheet just use that class to hide!
Your prose translates to this CSS:
!tr>td>input:matches(:not([value]),[value=''])
However, both ! and :matches are CSS4 selectors that are not implemented yet. You'd be better off using JavaScript:
var qsa = document.querySelectorAll("tr>td>input"), l=qsa.length, i;
for( i=0; i<l; i++) {
if( qsa[i].value == '') qsa[i].parentNode.parentNode.style.display = "none";
}
Try using the :has() selector: http://api.jquery.com/has-selector/
Description: Selects elements which contain at least one element that matches the specified selector.
$('tr:has(td input[value=""])').css({color:'red'});
I have been able to select the specific rows that I wanted but I can't select specific td from those tr.
I used this to select rows:
$('#time-slot tr:not(:first, :last)')
then within those selected rows I was trying to ignore the first and the last td but it is not working. I used similar approach as above
$('#time-slot tr:not(:first, :last) td:not(:first, :last)')
Any ideas how should I approach this problem. Btw I am trying to click and drag the mouse to paint the cells with user defined color.
I prefer using less of a string selector and more of the jQuery methods, as well as using the :first-child and :last-child selectors for your problem:
$("#time-slot").find("tr").not(":first-child, :last-child").find("td").not(":first-child, :last-child").addClass("active");
http://jsfiddle.net/7b4Ms/
Depending on what you are expecting, which you haven't explained very well, this may or may not be what you want. What this does is select all tr elements that are not the first and last. Inside of those matched tr elements, it selects all td elements that are not first and last. So basically, it doesn't select the outside ring of cells in the table.
Totally agree with Ian, just I prefer to use .children() instead of .find(). Because it can make a problem if you have nested tables.
$("#time-slot").find("tr").not(":first-child, :last-child").find("td").not(":first-child, :last-child").addClass("active");
changes to:
$("#time-slot").children("tr").not(":first-child, :last-child").children("td").not(":first-child, :last-child").addClass("active");
Try this (uses css selectors only):
$("#time-slot tr:not(:first,:last) td:not(:first-child,:last-child)").addClass("active");
Sample
I am using this jQuery selector multiple times in my JSP:
$("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")
The solution I found on some blogs is that I should do first:
var customer=$('#customers')
And then use the above customer object for further calls.
customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")
My question is, does this solution will make any difference and why?
My understanding
When I do
$("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']")
jQuery internally will first get the object associated with div id="customers"
(by document.getElementById("customers")) and then will traverse to the specified
checkbox. And if I go by the suggested solution then document.getElementById("customers") will be fired only once and the rest will be the same. So I am saving myself from unnecessary multiple document.getElementById but the rest will be the same. Is my understanding correct? If yes is, just for the sake of my knowledge, is document.getElementById a more costly operation?
EDIT:-
i am not using only above said selector multiple times but also other possible selector under div id="customer". So question again is whats is difference in terms of performance if I cache the customer object first and if i don't do it?
There is no way you need to be that specific. I'm guessing, at the very most, this:
$('#customers td [name="selectedCustomers"]')
... which should improve performance. Next, if you're actually querying for selectedCustomers each time, you should cache the whole thing:
var selectedCustomers = $('#customers td [name="selectedCustomers"]');
Otherwise, if the name is dynamic, and you only have one item with the same name per page...
var item = $(document.getElementsByName(someName)[0]);
Caching just $('#customers'), on the other hand, is pretty much pointless. .find on customers will do just as much work as the whole selector in the first place, especially with querySelector support.
You seem to be missing the fundamental point of caching the object. Once the object is cached, any further traversal or manipulation within that selector will be performed on the stored object and doesn't require a search of the DOM to first locate the selector and create the collection every time you need to use it
Every time you call $("#customers tbody tr td input[type='checkbox'][name='selectedCustomers']") a search of the document has to be performed to create the collection of elements before any changes can be made to the collection.
Caching the collection means no further searches need to be made therefore improving performance
/* locate and store the collection once*/
var $checkboxes=$("#customers tbody input[name='selectedCustomers']");
/* look within previously stored collection*/
$checkboxes.filter(/* expression*/ ).doSomething();
Using document.getElementById will be faster than a jQuery search, simply because it doesn't require addiitonal function calls made by jQuery library. However if you wish to use result as a jQuery object like:
$( document.getElementById('foo'))
the gains are likely not worth worrying about for a single use to cache an object
So I am saving myself from unnecessary multiple document.getElementById but the rest will be the same.
Yes. But maybe also no, as selectors are evaluated from right to left (see this article or this SO question). And assuming an efficient engine, it had less work to do if it does that evaluation only on a part of the document tree if you first select #customers and then .find() in it. But I'm not 100% sure about that.
Is document.getElementById a more costly operation?
No, it is very cheap. Ids are the standard attribute to identify single elements, and browsers will build very performant lookup tables for it - you can assume it to be nearly O(1).
customer.find("tbody tr td input[type='checkbox'][name='selectedCustomers']")
On the other hand, DOM selector queries which need to evaluate the DOM tree are very costly, especially if done manually in JS code (jQuery sizzle) and not native - though this rather simple query will be delegated to the native querySelectorAll.
I am guessing that #customers is your table element. So for performance, omit the tbody tr td tags, they are obligatory (assuming you have not used them to explicitly exclude checkboxes from <thead>/<tfoot> or <th> elements). You will not find an <input> as a direct child of a table element anyway - and the selector engine has much less to do.
Further, if you know your markup well and can make the assumption that only checkboxes have that name attribute, you might omit the tagname and type attribute selectors as well. And that means you can delegate to the native getElementsByName, which should boost performance a little bit again:
$(document.getElementById("customers").getElementsByName("selectedCustomers"))
If you need to check for the elements to be checkboxes, you still could filter them. With that, you might end up with
$(customer.get(0).getElementsByName("selectedCustomers")).filter(":checkbox")
However, to proof the performance gains you only can test, test, test; and you'll need to do that on your actual full page.
http://jsperf.com/different-jquery-selector-tests
Check out this little test. Basically $('#div').find('#p'); is the fastest and $('div').find('#p'); is the slowest.
I have an empty table in my code like so:
<table id='rostertable'></table>
When I add a <tr> using jQuery's append function, then according to my chrome inspector, my table looks like this:
<table id='rostertable'><tbody><tr>...</tr></tbody></table>
It seems like the tbody got added by itself, and this causes problems later when I'm traversing the DOM.
For consistency's sake, I figured it would be better if I added the tbody myself and appended directly to it. Is this possible? I tried making my placeholder <table id='rostertable'><tbody></tbody></table> but the jQuery selector $('#rostertable tbody') returns null and my chrome inspector doesn't show the tbody tags either.
Edit: Never mind, it ended up being an unrelated bug in my javascript. At one point I was clearing out the contents of the table and running $("#rostertable").html(""), which of course deleted the tbody. I accepted the first valid answer to this question.
You should not get null, if no element matches the selector still you will get object containing zero elements.
Your selector is returning tbody and you might be using some wrong method.
Live Demo
alert($('#rostertable tbody').html());
To append to the tbdoy your code should work as long as you append valid html.
The below works ok:
$('#rostertable tbody').append('<tr><td>new row - cell 1</td><td>new row - cell 2</td></tr>');
DEMO
You need to make sure you append a <td> as well as the <tr>. For example in Chrome, the following will simple add an empty <tr>
$('#rostertable tbody').append('<tr>no cells added, just row</tr>');
This may sound like a simple question, but I just cannot seem to find an answer on google, probably because the search term will bring back quite a lot of irrelevance.
I would like a jQuery selector to select all odd table rows, that are not in <thead> and apply a css class to them all.
table.cp-ss-grid tr:odd
The above selector will bring back all odd rows in the table correctly, but will include the thead rows (on ie)
How would I in the selector do an and, i.e. something like:
table.cp-ss-grid tr:odd:not(thead)
the above doesn't work and still brings back the thead rows
Any ideas?
An AND selector for jQuery would be for example: .classA.classB
This would select elements which have classA and classB.
Why not do:
$('table.cp-ss-grid > tbody > tr:odd');
To explicitly select the body rows? All browsers will add a tbody for you if you don't have one.
if you use th to head and td to other rows ,
you can check that the have child of td,
.children('td')
table.cp-ss-grid tr:odd select all the odd rowb which will not include the header
if you want to specify a color of the header use :nth-child(n)