Given the following HTML:
<fieldset>
<legend>
<input type="checkbox" name="amazon_activated" />
</legend>
<table>
<tr>
<td>
Amazon Data
</td>
</tr>
</table>
</fieldset>
next code allows hide/show the data container table related to the checkbox:
$("input[name='amazon_activated']").click(function(){
$(this).parent("legend").next("table").toggle( $(this).is(":checked") );
});
and next code it should init the hide/show state after page's load:
if ( ! $("input[name='amazon_activated']").is(":checked")){
$(this).parent("legend").next("table").hide();
}
Well, it is failing.
I already know why: this refers to the page element, not the checkbox element.
So I wonder:
Is it the best policy immediately choose an id/class:
$("#id")
for the important elements in order to facilitate their control through jquery, over form-based selectors?:
$("input[name='amazon_activated']")
Cache the element.
var element = this;
When this is in the right context.
You usually code Javascript for a given markup, not the other way around. ID's and classes have meaning other than being used as selectors.
I think you can cache your elements at the top of the outer function. It will be convenient to use them in other places. Also, caching elements will also enhance the performance.
You can do something like this:
var input = $("input[type='checkbox']"),
table = $("fieldset table");
if ( ! $("input[name='amazon_activated']").is(":checked")){
$(this).parent("legend").next("table").hide();
}
within above code this belong to page element scope, where
$("input[name='amazon_activated']").click(function(){
$(this).parent("legend").next("table").toggle( $(this).is(":checked") );
});
in above code this belongs to input[name='amazon_activated']'s callback scope which point to input[name='amazon_activated'].
So to make active first code you should try
if ( ! $("input[name='amazon_activated']").is(":checked")){
$("input[name='amazon_activated']").parent("legend").next("table").hide();
}
Its better to keep reference of input in a variable and use that
var checkboxElement = $("input[name='amazon_activated']"); // you can also use id
then you this like
if ( ! checkboxElement.is(":checked")){
checkboxElement.parent("legend").next("table").hide();
}
checkboxElement.click(function(){
$(this).parent("legend").next("table").toggle( $(this).is(":checked") );
});
I think the reason every answer is telling you to cache your objects is that it will be tremendously faster. To answer the specific question, disregarding the rest, i.e.:
Is it the best policy immediately choose an id/class for the important
elements in order to facilitate their control through jquery, over
form-based selectors?
First, I would say "attribute selectors" over "form-based selectors" as I don't believe jQuery distinguishes between, say $('input[name="amazon_activated"]') and $('a[href="#"]') as far as how it searches.
That said, the general rule of thumb is:
id selectors are faster than class selectors are faster than attribute
selectors.
So, if all you care about is jQuery speed, that's key. However, adding ids and classes, only for the sake of targeting via jQuery could slow down your page load times more than the corresponding speed-up in selector performance.
In summary to this overly-long answer:
Cache the result of a jQuery selector when possible
Use ids and classes when possible, but
Don't add unnecessary ids and classes unless testing proves them necessary
Thanks to all for your answers. All have been very helpful (I give +1 to all).
I want to add my final solutions that takes in account your tips.
Indeed there are several checkbox elements involved, so I have cached them and use an associative array to iterate over it (avoiding add more id/class).
var checkboxElements = {
"amazon_activated" : $("input[name='amazon_activated']"),
"clickbank_activated" : $("input[name='clickbank_activated']"),
"ebay_activated" : $("input[name='ebay_activated']")
}
$.each(checkboxElements, function(i, el){
$(el).parent("legend").next("table").toggle( $(el).is(":checked") );
$(el).click(function(){
$(el).parent("legend").next("table").toggle( $(el).is(":checked") );
});
});
Related
On an HTML page which repeats a nested structure like
<div>
<div class="ugga">
<button class="theButton">
</div>
</div>
several times, with one ".theButton" also having class "active", I would like to use jquery to find the button after the active button.
$(".theButton .active").parents(".ugga").parent().next().find(".theButton")
would roughly do the trick. However, this is still under development, so that I am not sure that the nesting level div/div/button as well as the parent element with ".ugga" will be stable. So whenever there is a structure change on the HTML side, I would have to change the above jquery-magic accordingly.
What is stable is that there will be a list of ".theButton" elements at some nesting level and all on the same nesting level.
Is there a simple way in Jquery to find the next button after the active one even if the structure is changed to just div/button or to form/div/div/button and the ".ugga" I rely on currently disappears? Something like
$(".theButton active").nextOnSameLevel(".theButton")
There's no short and simple solution I know of, which would let you to do that.
The most convenient way would be to have the HTML ready before setting up javascript for DOM manipulation. Even thinking of project updates I would personally spent that little while to change a small part of js.
However, if that's needed for some reason, then I would probably loop through the elements, to find the one I need, eg.:
var found = false;
$(".theButton").each(function(){
if(found){
// do something with $(this) ...
return false;
}
if($(this).hasClass('active')){
found = true;
}
});
JSFiddle
And yet another, oneliner solution:
$(".theButton").eq(($.inArray($(".theButton.active")[0], $(".theButton").toArray()))+1);
JSFiddle
This is for looking at all the other elements having the same parent as your element of interest.
$(".theButton active").siblings(".theButton");
This will return all the elements having theButton before and after your active button elements but if you're looking specifically for the element after active, use next() with a selector like this
$(".theButton active").next(".theButton");
I use a current jQuery selector to apply css to any elements containing certain keywords on YouTube as listed below:
$( '.feed-item-container:contains("Blah Blah") ') .css( {"display":"none"} );
My question is, how can it be changed so instead of using keyword detection, it can instead use a number detection range for each youtube feed on the subscriptions page(signed in)? If the element used to display the view count in the specific element ".feed-item-container", then how can that element(".feed-item-container") that displays each video/feed to apply css to hide it, but detect a number range for an element in it for ".yt-lockup-meta-info" containing 0 to 300 views?
To be clear, I do not need it to detect keywords and view count, only removing the parent element (by class selector) if the child element (by class selector) contains 1-300 views; already have jQuery to hide by keyword.
The closest I have gotten but incorrect:
$( ".feed-item-container:has(.yt-lockup-meta-info > :last-child)" ).slice(1, 300).css( "display", "none" );
I just realized moments later of why it wasn't working; thus realizing .slice, only selects elements and not number ranges such as 1-300.
I understand this may or may not be a complicated problem, but my knowledge of jquery does not go down this path of understanding. Any help is much appreciated, but if solvable it would be very appreciated. This may help: http://jsfiddle.net/fVtaF/7/ + http://jsfiddle.net/eWweU/4/ (doesn't work)
I wonder if this FIDDLE, as a concept, would be helpful.
Using the JS $('#containme').text().indexOf( i ) > -1you can assign a variable to the .indexOf, and loop through a series of variables to see if there is a matching number in your element.
Lots of "overhead". I'm sure there are more elegant ways.
I'm not 100% sure of what you're asking, but if I understand you correctly maybe this fiddle will help you: http://jsfiddle.net/eWweU/3/
It uses jQuery to test every child of the feed-item-container class to see if it has a number from 0-300. If it does, it will hide that feed-item-container container.
Good luck.
I have a site that has multiple divs with the same id name. I want to set a mouseleave function for all of the divs that have this id. In my $(document).ready function I have this code...
$('#my_post_container').mouseleave(function(e)
{
hideSnippet();
});
My hideSnippet() function is correct, but doing this only set the mouseleave function for the first time that a div comes up of id my_post_container. Is there a way to set the mouseleave function to all divs with this id?
I have a site that has multiple divs with the same id name.
Then you need to fix that. You must not have more than one element with the same id. id values must be unique on the page.
You probably want to use class instead, at which point your code is basically fine:
$('.my_post_container').mouseleave(function(e)
{
hideSnippet();
});
...although it coudl be shortened a bit if hideSnippet doesn't care what arguments it gets, doesn't care about this, and doesn't return false:
$('.my_post_container').mouseleave(hideSnippet);
It is invalid HTML to have multiple objects with the same id. As such, you cannot use normal selectors to find them all and you should fix your HTML to not do that.
The #1 suggestion is to fix the HTML so it does not have multiple objects with the same ID. Use a class name and you can then select them all with getElementsByClassName() or querySelectorAll() or with jQuery selectors as in:
$('.my_post_container')
If you insist on having multiple objects with the same id (a bad choice), then you will have to somewhat manually iterate over all possible objects that could have that id.
$("div[id='my_post_container']");
But, this is pretty darn inefficient because the browser can't use any of the built-in selector engine logic and it could break in the future if jQuery decides to optimize this. You really ought to switch to using class names.
You can not have multiple elements on the same page with the same id. Use a class instead, as shown here:
HTML:
<div class="my_post_container">...</div>
<div class="my_post_container">...</div>
<div class="my_post_container">...</div>
jQuery:
$('.my_post_container').mouseleave(function(e)
{
hideSnippet();
});
First of all there should not be any div elements with same ID name.. first we should solve that by keeping class name same.
then on mouse leave and enter part..
$(".testClass").on({
mouseenter : function() {
$(this).css({"background-color" : "blue"});
},
mouseleave : function() {
$(this).css({"background-color" : "green"});
}
});
this should work.. will add a js sample http://jsfiddle.net/meVc6/
and the same thing can be achived using css too..
just add css .testClass:hover { background-color:blue}
This question is related to performance.
If I use a selector like the following
$('#myID a') // Does this find #myID and filter by a?
Or should I write the statement like this?
$('#myID').find('a')
I'm not sure if jQuery is smart enough to execute this statement using the ID first or if it operates exactly like CSS and reads right to left. It's not such a big deal using tags but when you run something like
$('#myID .myClass')
It makes a HUGE difference in performance.
From a NetTuts article: http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-think-right-to-left-with-jquery/
As an example, if Sizzle comes across a selector like $('#box p'),
it’s true that it works right-to-left, but there’s also a quick regex
optimization that will first determine whether the first section of
the selector is an id. If so, it’ll use that as the context, when
searching for the paragraph tags.
Relevant comment from SizzleJS:
// Take a shortcut and set the context if the root selector is an ID
// (but not if it'll be faster if the inner selector is an ID)
When an Id is in the selector. jQuery will first execute document.getElementById then begin filtering for child elements.
basically this is why it is never a great idea to use just attribute or class selectors $('.someclass') or $('[name=myname]') without being more specific. Because it causes the code to traverse the DOM and look at every element to find that class.
By just adding a tagname to the same selector $('div.someclass') or $('div.[name=myname]') you improve efficiency becuase it will first run. document.getElementsByTagName narrowing the number of elements to search.
HTML markup:
<div>
<a id="foo"> </a>
</div>
jQuery:
$('div').each(function(){
$('#foo', this).dosmth(); // 1
$('#foo').dosmth(); // 2
});
Which method would be faster to run dosmth?
Since we're getting a variety of answers, hopefully here's some clarity (check the examples here):
The fastest - There's no need to loop. Skip the $("div").each part and just do $("#foo"). foo is an ID, and thus lookup is instantaneous.
Middling - $("#foo") in a loop. Note that you also don't want this because it will execute the function for every div on the page (and for this reason on a larger document with a lot of divs this would be the slowest).
Slowest - $("#foo", this). The context node doesn't help in the first place, and then consider that jQuery will first build a jQuery object out of this and turn it into $(this).find("#foo"). That's all unnecessary, of course.
Bottom line: in most cases (e.g. sometimes when confirming that an ID is in one context and not another) context nodes are unnecessary with ID lookup.
Here are some resources from the jQuery source:
Handling for most of the cases here - note that $("#id") is singled out for handling as document.getElementById
find - what happens when you pass a context
Since an #id should be unique in the DOM your markup will be invalid (I am assuming more than one <div/> based upon using .each())
Change the id to a class and use the following:
<div>
<a class="foo"> </a>
</div>
<div>
<a class="foo"> </a>
</div>
And the script
$('div').each(function(){
$('.foo', this).dosmth(); //or $(this).find(".foo");
});
But if you only have one element with an id of foo selecting by id will be the fastest, plus you can drop the need for using .each()
$('#foo').dosmth(); //or document.getElementById("foo");
jquery selectors by id only is the fastest way to search because it uses getElementbyId in javascript.
so this one is the fastest:
$('#foo').dosmth();
if you use a context like:
$('#foo', this).dosmth();
it is translated into:
$(this).find('#foo').dosmth();
so that will make another useless operation because your #foo is unique
Regards,
Max
$('#foo', this).dosmth();
This will search within the context of the div and not the whole DOM, which will make the selector faster. This only makes sense to use when the DOM is large, otherwise, just use the normal selector: $('#foo').dosmth();
If you're using an id there's only ever going to be one. So you can just do:
$('a#foo').dosmth();
You don't need to use each() to go through each div and get all the a#foo's out of it. That WILL waste time, creating loops for no reason. Instead use:
$('a#foo').each(function(){ ... });
or even just:
$('a#foo').dosmth();
You can also do $('div a#foo').dosmth(); if you want.
Please read the discussion below regarding this answer or check Bryan answer above about the differences in speed of the selectors.
I would go with
$('a#foo', this).dosmth();
Update But instead of retrieving all the divs before, I would check for
only the desired one at the first time
like this
$('div a#foo').each(function(){
}