how to change css with jquery and .each? - javascript

I have several div with the .item class and want to change the css if the id is 1
</div>
<div class="item" id="0">
</div>
$('.item').each(function(i){
var estatus = $(this).attr('id');
if (estatus == '1')
// change only item with id = 1
});

Just modify your selector...
$('#1').css('whatever', 'yep');
Please see the comments section to see why this works in this scenario, but you're gonna have bad time if selecting it in a stylesheet. I'd recommend using the method in T.J.'s answer, because of jQuery ever switch to funnelling these calls through querySelectorAll(), it will blow up).
My recommendation is to not use id attributes that start with a number.

With CSS, it's awkward to use id values starting with a digit; the simplest thing is to avoid using them.
But with what you have, you can do this:
$(".item[id='1']").css(/*...*/);
Just using #1 as a selector may work in certain select situations provided they don't rely in CSS parsing, but is invalid. If you must have an id value starting with a digit, to use it with a CSS selector, you have to escape it. The escaped version of #1 is #\31, which gets even more awkward when written as a JavaScript string: $("#\\31").css(/*...*/);.
But this works and is in-spec:
$("#\\31").css(/*...*/);
This works in jQuery as of the current version and is not in spec:
$("#1").css(/*...*/);
It could stop working at any time, however, as it's not in-spec, and breaks if you combine it with various things.

Related

I can't find any documentation on this CSS selector.. what is it?

I am using jQuery to change the width of a sidebar, and within the working code on CSS it shows this:
#wrapper.MenuDisplay #my-sidebar-wrapper {
width: 200px;
}
But after looking through w3schools and mozilla etc, I have not found any selector which looks like #foo.bar.
The reason I am trying to figure this out is that I can't understand why this CSS isn't applied straight away, and how a jQuery toggleClass is able to get this width to be applied (which it successfully does) on a button click.
Does anyone know what is going on here? What the selector is and why it works after clicking on a jQuery button but not straight away on page load?
Many thanks
That means element with id foo and class bar, shortened to #foo.bar
[id][class]
#wrapper is id of an element, and .MenuDisplay is class. Element must have that id and class to get that CSS work.
#foo.bar
matches an element that has both id = "foo" and class = "bar".
It appears you are asking what a sequence of selectors means.
According to current W3C standard, it is...
...a chain of simple selectors that are not separated by a combinator. It always begins with a type selector or a universal selector. No other type selector or universal selector is allowed in the sequence.
Not everyone considers the second sentence of the definition true, because, for example, #this or .that appear not to begin with either a type selector (a, div, span, etc...) or a universal selector (*). However, one should bear in mind that...
...whenever a sequence of selectors does not begin with a type or universal selector, it "defaults" to starting with an omissible universal selector.
So, #this is a shorthand for *#this, .that is a shorthand for *.that. And #this.that is a shorthand for *#this.that.
In fact, if you read the entire universal selector paragraph, you'll notice a note at its end recommending it not to be omitted.
However, almost nobody respects this recommendation and, in practice, the only time you'll see a universal selector is when someone wants to give a CSS property to every single element in the page.
Like in * {box-sizing: border-box;}
As a side note, not omitting the universal selector in your CSS is supposed to make it faster. This is not difficult to test and appears to be true, but the differences are negligible.
Well As far as I can understand from your question,
jQuery Selectors allow you to select and manipulate HTML element(s) or select HTML elements based on their name, id, classes, types, attributes, values of attributes and much more. It's based on the existing CSS Selectors, and in addition, it has some own custom selectors.
In this case:
#foo.bar points to an element in the DOM that has an id="foo" and a class="bar".
jQuery Selector Tester to demonstrate the different selectors:
jQuery Selectors Test Page
Hope I could help!
#foo.bar refers to the element with together foo id and bar class.
$('#foo.bar').fadeOut('slow');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='foo' class='bar'>box</div>

JQuery "#id.class" Selector Mashup

I have some bullet points which I want to show more text below them on clicking them. They are both two separate Ps that are paired together by sharing a common id. So, what I am trying to do below is to find the element with (id_same_as_this.class), so that the element with the class "expand" as well as the id that matches the clicked on P is toggled. Does that make sense?
$(document).ready(function(){
$(".expandable").click(function(){
$(this.attr('id')+"."+"expand").toggle(800);
});
});
I only ask if the above code could be made to work because it would make the expandable bullet points in my web page significantly less code intensive than a lot of the examples I have read about.
$(this.attr('id')+"."+"expand").toggle(800);
Must be
$("#" + this.id +".expand").toggle(800);
You missed the # there. That said, you shouldn't ever have a common ID. By definition IDs are meant to be unique. If you have the same ID on multiple elements, while it may work now on the browsers you try, you have no guarantee it won't break in the next rev of jQuery (or Chrome, or Konqueror, or iOS Safari). There's also no reason to do it. You could just use classes or data-* attributes.
Yes this will work but you need a # before the ID
They are both two separate Ps that are paired together by sharing a common id.
IDs are unique. Two elements can't share a common ID, as that defeats the whole purpose of having a unique identifier. JavaScript assumes that you're using valid HTML, so document.getElementById() will return only the first element with a matching id. By using non-unique IDs, things will start breaking in unpredictable ways:
$('#foo').find('.bar') // Won't search past first #foo
$('#foo .bar') // Will search past first #foo in IE8+
Try restructuring your HTML to make this task easier. Maybe you could do something like this:
<ul id="bullets">
<li>
<h2>Title</div>
<div>Text</div>
</li>
</ul>
And then use a simple event handler:
$('#bullets h2').click(function() {
$(this).next().toggle(800);
});
You don't need id values for this at all (which is good, as from the comments on hungerpain's answer, you're using the same id value on more than one element, which is invalid).
Just do this:
$(document).ready(function(){
$(".expandable").click(function(){
$(this).find(".expand").toggle(800);
});
});
That will find the element with the class expand within the expandable that was clicked. No relying on unspecified behavior of selectors.
If you really need that data on the expandable, just put it in a data-* attribute. So instead of this invalid structure:
<!-- INVALID -->
<div id="foo27" class="expandable">
<div class="expand">...</div>
</div>
<div id="foo27" class="expandable">
<div class="expand">...</div>
</div>
Do this
<!-- VALID -->
<div data-id="foo27" class="expandable">
<div class="expand">...</div>
</div>
<div data-id="foo27" class="expandable">
<div class="expand">...</div>
</div>
Use the above code to do the expansion. If you need the value, use .attr("data-id") or .data("id") to get it.

Multiple not() DOM Selectors

I want to select a particular node with two not clauses, but I had no success so far. What I need to do is, select an element whose div contains the string 0008, but it's not 10008 and also it does not contain the tag "style", so, in theory it should work like that:
document.querySelectorAll(" div[id*='0008']:not([id='10008'][style])")
However, as you might suspect, it doesn't work that way.
document.querySelectorAll(" div[id*='0008']:not([id='10008'])")
document.querySelectorAll(" div[id*='0008']:not([style])")
Both of them work perfectly individually, of course.
not 10008 and also it does not …
That's not what your current selector checks, it test whether it has not ( the id and a style attribute ) . Use this instead:
div[id*='0008']:not([id='10008']):not([style])
Your original solution also was not a valid selector, since :not() may only contain one simple selector, while you had two of them. Yet, selector libraries like jQuery's sizzle engine might support them. So with jQuery, the following would work as well:
div[id*='0008']:not([id='10008'],[style])
jsFiddle Demo
Logically, you are trying to exclude elements that match either of the two undesired selectors, not elements that match them both. In jQuery, the multiple selector (which will then match all of the undesired elements, then be negated) is simply a comma-separated listing. Therefore you simply do this:
$("div[id*='0008']:not([id='10008'],[style])")
From the jQuery docs (since this question is tagged jQuery):
All selectors are accepted inside :not(), for example: :not(div a) and :not(div,a).
I'd just do:
var elems = $('div[id*="0008"]').filter(function() {
return !this.hasAttribute("style") && this.id == '10008';
});
I don't think I really get this, but this would filter out:
<div id="10008" style="color: black">10008</div>
but not:
<div id="10008">10008</div>
ID's are of course unique, and there could be a real world use case for this, but it still seems like an edge case that you'd normally handle some other way, as once you'd filtered out the ID, why exactly do you need to match a style tag as well ?

Will jQuery search for the ID before filtering other parameters in the selector?

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.

Performance of jQuery selectors

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(){
}

Categories