Select only (display:block) element from list of items Jquery - javascript

I'm making a menu and i need to select one particular element from a list of element returned by Jquery.
When i run on console :
$("[type='subMenu']")
This returns 4 matching submenu elements.
<div type="subMenu" style="display:block">
<div type="subMenu" style="display:none">
<div type="subMenu" style="display:none">
Now, i need to select only the element having display:block
I tried
$("[type='subMenu']").css('display') == 'block'
but this give false as output.
and
$("[type='subMenu']").css('display')
this is giving output as none

Others have already pointed out the JQuery :visible selector. However, there are some performance issues with it, as pointed out in the JQuery API documentation:
Additional Notes:
Because :visible is a jQuery extension and not part of the CSS specification, queries using :visible cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :visible to select elements, first select the elements using a pure CSS selector, then use .filter(":visible").
Using this selector heavily can have performance implications, as it may force the browser to re-render the page before it can determine visibility. Tracking the visibility of elements via other methods, using a class for example, can provide better performance.
If you'd prefer to avoid those issues, you could use a native CSS selector, instead. In plain ol' normal JavaScript, this would do the trick for you:
document.querySelector("[type=subMenu][style*=display\\:block]");
Or, if you need to select multiple elements at once:
document.querySelectorAll("[type=subMenu][style*=display\\:block]");
I believe the equivalent in JQuery (I don't use it) for both would be:
$("[type=subMenu][style*=display\\:block]");
If the only style that will ever be set inline on those tags is display then you can omit the * from the style attribute selector.

Try this:
console.log($("[type='subMenu']:visible")).
It will give all visible elements

You can use filter or pseudo class.
$("[type='subMenu']").filter(function(){
this.style.display == 'block';
});

Related

jQuery's show/hide won't work with elements not attached to DOM (breaking change found in 3.0)

I am working on upgrading big application to latest jQuery 3.0 from pretty ancient 1.11.2. I found pretty subtle change that broke some of our functionality:
when we instantiate some complex widgets, we initially hide some of the elements using css (display none). Then we use show/hide to display the element.
But call to show/hide can happen before widget is attached to DOM. Show/hide used to work fine in 1.11.2 when element was not attached, but does not work in 3.0.0.
Demo:
1.11.2: https://jsfiddle.net/7j9xawc2/1/
3.0.0: https://jsfiddle.net/vma214mL/1/
.tabCompositeSearchWidget-ClearButton
{
/* Clear button is initially hidden */
display: none;
}
var e = document.createElement('div');
$(e).addClass('tabCompositeSearchWidget-ClearButton');
$(e).text('blah');
$(e).show();
$('#root').append($(e));
alert($(e).is(":visible"));
In the old version element will be visible and alert will say true, in the most recent it won't be visible and alert will say false
It is hard to find all of such usages and I am interested in the best way of fixing that:
what can be the best fix here? Manually modifying jquery.js file to behave it the old way? (I don't really want to do that)
Upd: fixing one-off case is easy. But have potentially tens of such calls and finding & fixing all of them needs huge effort and is not effective.
Here's the relevant section from the jquery blog:
"If you have elements in a stylesheet that are set to display: none, the .show() method will no longer override that. So the most important rule for moving to jQuery 3.0 is this: Don’t use a stylesheet to set the default of display: none and then try to use .show() – or any method that shows elements, such as .slideDown() and .fadeIn() – to make it visible.
If you need an element to be hidden by default, the best way is to add a class name like “hidden” to the element and define that class to be display: none in a stylesheet. Then you can add or remove that class using jQuery’s .addClass() and .removeClass() methods to control visibility. Alternately, you can have a .ready() handler call .hide() on the elements before they are displayed on the page. Or, if you really must retain the stylesheet default, you can use .css("display", "block") (or the appropriate display value) to override the stylesheet."
https://blog.jquery.com/2015/07/13/jquery-3-0-and-jquery-compat-3-0-alpha-versions-released/
try $('div') instead var e = document.createElement('div');

Javascript vs. CSS for swapping elements

I have a rather lengthy (~100 fields) form that has certain elements which are toggled between a "quick" and a "full" quote. This toggles 75 of the fields from hidden to visible. Currently, I do this via some simple jQuery:
jQuery('.full_quote').show();
jQuery('.quick_quote').hide();
I realized that this could be accomplished in a different way using CSS to do the work for me:
## Javascript:
jQuery('#quote_form').toggleClass("full_quote quick_quote");
## CSS:
form.toggle-form.full_quote .quick_quote {display: none;}
form.toggle-form.quick_quote .full_quote {display: none;}
So the bulk of the question is: Which is better to use when performance is concerned?
My initial thought is that the overhead of iterating over the results in jQuery will take more time than the CSS. I do not have a way to test this, however, so I'm curious the community's experience.
Rather than defining new custom classes, or using jQuery's show and hide methods, I'd actually advise a third option.
Add a [hidden] attribute to whatever element needs to be hidden, and remove the attribute when it needs to be shown:
JS:
$('.foo').attr('hidden', true);
To make sure that this is supported cross browser, you'll need to add a bit of CSS:
CSS:
[hidden] {
display: none !important;
visibility: hidden !important;
}
This also gives you the ability to override how "hidden" elements are styled, which can be useful for debugging.
When you want to show the element, simply remove the [hidden] attribute:
JS:
$('.foo').attr('hidden', false);
It would be nice if jQuery implemented show and hide to utilize [hidden], instead developers need to take care when using show as it will override any stylesheet declarations for display when it adds a display style inline.
Both are essentially the same. JQuery does a very similar the same logic internally. (See How does jquery's show/hide function work?). And it is not like your CSS apprach does not use javascript at all (in that case, it would be the better option)
So,
jQuery('.full_quote').show();
jQuery('.quick_quote').hide();
makes sense (you are using JQuery anyway, why not use all of its functions) s a lot more readable, and

How is the jQuery selector $('#foo a') evaluated?

As a example of jQuery code (https://coderwall.com/p/7uchvg), I read that the expression $('#foo a'); behaves like this:
Find every a in the page and then filter a inside #foo.
And it does not look efficient.
Is that correct? And if yes, how should we do that in a better way?
That is correct - Sizzle (jQuery's selector engine) behaves the same way as CSS selectors. CSS and Sizzle selectors are evaluated right-to-left, and so #foo a will find all a nodes, then filter those by nodes that descend from #foo.
You improve this by ensuring that your leaf selectors have a high specificity, usually by giving them a class or ID.
how should we do that in a better way?
Use the context parameter from jQuery.
$('a', '#foo');
Now jQuery will search all anchors within the context of the element with id: foo.
In your query the context is defaulted to document when omitted:
$('#foo a'); == $('#foo a', document);
In this case, your query is indeed not efficient.
You might take a look at this article.
While it is true that Sizzle is a right-to-left engine (which is the same way css is interpreted), it is not true that the specific selector in your example would select all anchor elements on the page and then filter their parents to match the id of "foo". Sizzle actually optimizes any selector that starts with an ID and uses that as the context for the entire selection, rather than using the document. In other words, the selector you've chosen basically translates to:
document.getElementById("foo").getElementsByTagName("a")
Really, that's not a bad selector at all.
However, given the other things jQuery needs to do (which includes looping over the elements to merge them onto the jQuery instance), jQuery("#foo").find("a") will always be the fastest because jQuery implements a jQuery object creation shortcut for id-only selectors, and then it does the find rooted from #foo.
In other words, Sizzle itself is not much different when doing Sizzle("#foo a") and Sizzle("a", document.getElementById("foo")), but jQuery("#foo").find... will be faster because of jQuery's own ID shortcut.
By the way, my remarks on Sizzle is assuming querySelectorAll is not being used. If it is, Sizzle just passes it on to qsa, which still isn't as fast as using jQuery's ID shortcut.
You can use find() for more granular control on your selector order:
$('#foo').find('a');
This will of course be more impressive with more complex selectors, where you can chain find() and filter().
For the record $('#foo').find('a') === $('a','#foo')
[Update] ok, I realized later that it's exactly what your link says...
The jQuery selector engine (Sizzle) has been refactored last year, you'll find detailed explanations here:
http://www.wordsbyf.at/2011/11/23/selectors-selectoring/
Instead of filtering with a inside #foo elements, simply attach a class to a elements and get a elements with class like $("a.class");. This would be more efficient.
Yet another "try it for yourself":
jsperf for various selectors on 10000 elements
jsperf for various selectors on 300 elements
jsperf for various selectors on a "more representative DOM"
Doesn't seem to be much difference with a "flat" DOM (1 & 2), but the performance varies much more with a nested DOM.
Also note that some of the test cases aren't selecting the correct elements (i.e. $('.a') vs $('.a', context)), but I left them from the original tests just for comparison.
This example will retrieve the all anchors elements a in an element called foo, to Find every a in the page and then filter a inside #foo as you want u should select a #foo
$("a #foo");
this will retrieve all the foo elements inside a elements.

"All but not" jQuery selector

I can select (using jQuery) all the divs in a HTML markup as follows:
$('div')
But I want to exclude a particular div (say having id="myid") from the above selection.
How can I do this using Jquery functions?
Simple:
$('div').not('#myid');
Using .not() will remove elements matched by the selector given to it from the set returned by $('div').
You can also use the :not() selector:
$('div:not(#myid)');
Both selectors do the same thing, however :not() is faster, presumably because jQuery's selector engine Sizzle can optimise it into a native .querySelectorAll() call.
var els = toArray(document.getElementsByTagName("div"));
els.splice(els.indexOf(document.getElementById("someId"), 1);
You could just do it the old fashioned way. No need for jQuery with something so simple.
Pro tips:
A set of dom elements is just an array, so use your favourite toArray method on a NodeList.
Adding elements to a set is just
set.push.apply(set, arrOfElements);
Removing an element from a set is
set.splice(set.indexOf(el), 1)
You can't easily remove multiple elements at once :(
$("div:not(#myid)")
[doc]
or
$("div").not("#myid")
[doc]
are main ways to select all but one id
You can see demo here
var elements = $('div').not('#myid');
This will include all the divs except the one with id 'myid'
$('div:not(#myid)');
this is what you need i think.
That should do it:
$('div:not("#myid")')
You use the .not property of the jQuery library:
$('div').not('#myDiv').css('background-color', '#000000');
See it in action here. The div #myDiv will be white.

jquery selector help

i have a event i trigger on every link in my site.
but then i want it to NOT trigger on links i've got class='nofocus' on.
for example
<a>link</a>
<a class='nofocus'>register</a>
$('a').live('click', function() {
$('#searchbox').focus();
}
how do i rewrite the $('a) so the second link wont trigger the event?
Theoretically, there are three options.
1. Using the “attribute not equal to” selector
The “attribute not equal to” selector matches elements that either don’t have the specified attribute or do have the specified attribute but not with a certain value.
$('a[class!=nofocus]')
This will only work as long as you don’t use multiple classes on your A elements in your markup, e.g. foo.
See Selectors/attributeNotEqual in the jQuery docs for more information.
2. Using .not()
Another option is to select all the A elements first, then filter the results, removing elements with class="nofocus" from the result set.
$('a').not('.nofocus')
This is more flexible, because it allows the use of multiple classes on A elements.
Also, it’s slightly faster than using The Attribute Not Equal To Selector™ in Firefox, but slightly slower in Safari.
See Traversing/not in the jQuery docs for more information.
3. Using the :not() selector
The fastest (and shortest) option is to use the :not selector:
$('a:not(.nofocus)')
Also, my tests point out that this is by far the fastest method of the three — more than twice as fast as using the attribute not equal to selector!
Performance comparison of the three options
I created a jsPerf test case so you can test this yourself: http://jsperf.com/get-elements-without-specific-class.
TL;DR: Use $('a:not(.nofocus)').
Try the :not() selector (docs):
$('a:not(.nofocus)').live('click', function() {
$('#searchbox').focus();
}
Selector: $("a:not(.nofocus)") will select all links without the nofocus class.
Use $("a:first"). http://docs.jquery.com/Selectors/first to just get the first one.
$('a:not(.nofocus)')
should do the job
http://docs.jquery.com/Selectors/not

Categories