Possible JQuery class selector bug - javascript

I have an ajax call that returns a HTML fragment. I am trying to select a div in that fragment before rendering.
An example of the HTML:
<div class="event-detail repBy-container">
<div class="copy">.....</div>
<div class="links">
....
</div>
<div class="contacts">
<div class="name-brand">....</div><div class="details">...., ...</div>
</div>
</div>
Now the problem:
function ajaxReturn(data) {
alert($(data).find('.event-detail').length); <-- Returns 0
alert($(data).find('.copy').length); <-- Returns 1
}
Is this a bug or am I doing something wrong?

.find() gets descendants only, not from the current level, you'd need .filter() to get items from the current set (which is the root of what you returned), like this:
function ajaxReturn(data) {
alert($(data).filter('.event-detail').length); //<-- Returns 1
alert($(data).find('.copy').length); //<-- Returns 1
}
If you want .find() to work in both cases, add the content to a parent container, like this:
function ajaxReturn(data) {
var parent = $("<div />").append(data);
alert(parent.filter('.event-detail').length); //<-- Returns 1
alert(parent.find('.copy').length); //<-- Returns 1
}

This is the expected behavior.
You are searching for .event-detail under your div and there isn't any.
You are searching for .copy under your div and there is one.

It depends on what is being passed into the ajaxReturn function. ie what does data contain?
If it contains the HTML you quoted then this is expected behaviour. This is because the .find() method searches within the current context, not including it. If the outer div in your example is the outer div in data then .find() will be searching for .event-detail inside of that div.

Related

jQuery cannot find class element from some html returned via ajax call

I am running an ajax call that returns some HTML as a string. For the purpose of this question I will call this <div class='abc'>ABC123</div> when I get this back I want to check and see if the class "abc" has a value and what that value is. However when I run a .find() I cannot find the class, I can find the div, but not the specific class. Just using the div is not adequate because in the real live code the HTML is very complex and has many divs and classes. Below is some JS that illustrates my point.
var x = "<div class='abc'></div>";
$(x).hasClass("abc"); // returns true
$(x).find(".abc"); // Returns empty array
Why is it that the first line returns true, but the selector cannot find the element?
Thanks!
Because $x is the div with class abc.
jquery .find() tries to find any children within the div.abc with class abc which it won't find.
This is more like it.
var x = "<div class='abc'><div class='def'></div></div>";
$(x).hasClass("abc"); // returns true
$(x).find(".def"); // returns $('div.def')
When we append html element to the page, sometimes JQuery can't find this element due to parent and child relationship.
For example: a button having class submit inside a div having id append_area and we want to run a function on click on this button. Then we can use the below code.
HTML Code:
<div id="append_area">
</div>
Jquery Code:
$("#results").delegate('.submit', 'click', function(){ });

Refer to attributes from multiple selector in jQuery

I have a bunch of DIVs identified by class screen-cat-comment and I want for each div to execute a plugin that receives as a parameter an attribute value from each DIV.
<div class="screen-cat-comment" catId="1"></div>
<div class="screen-cat-comment" catId="2"></div>
<div class="screen-cat-comment" catId="3"></div>
then, the selector
$('.screen-cat-comment').fragment({ code: $(this).attr('catId') });
Passing catId to myPlugin doesn't work -- from the current code, $(this).attr('catId') returns undefined. Is there any way to re-write this selector to pass attr('catId') to the plugin?
this in that context is probably the window...
$('.screen-cat-comment').each(function(){
$(this).fragment({ code: $(this).attr('catId') });
});

jQuery .index() strangeness

I'm by no means a jQuery (or JavaScript) expert so forgive me if I'm misunderstanding or overlooking something. I have the following HTML:
<html>
<body>
<div class="ted">Ted</div>
<div class="ted">Ted</div>
<div class="tim">Tim</div>
<div class="ted">Ted</div>
<div class="tim">Tim</div>
</body>
</html>
And the following JS:
$('.ted').click(function() {
alert($(this).index());
});
When I click a div with the class '.ted' the alert should show the index of that div.
Clicking the first div alerts '0' (expected), the second div alerts '1' (expected). However, clicking the last '.ted' div (the fourth in the list) alerts '3' - why is this not giving an index of 2? (as JS arrays are 0 based) and this is the third '.ted' div?
It's as if $('.ted') is actually bringing back all the divs in the list?
Example here: http://jsfiddle.net/nha2f/6/
The .index() method docs make this behaviour clear. Here's the relevant part (emphasis added):
If no argument is passed to the .index() method, the return value is an integer indicating the position of the first element within the jQuery object relative to its sibling elements.
Since the third element that matches your selector is actually the fourth child of its parent, it has an index of 3.
Continue reading through the documentation to find the solution to your problem:
If a selector string is passed as an argument, .index() returns an integer indicating the position of the original element relative to the elements matched by the selector.
So, you can pass the same selector to .index() and it will return the index of the element relative to the matched set:
alert($(this).index(".ted"));
.index() returns the index of the clicked element in it's parent, relative to it's siblings. Not compared to other divs with the same event listeners / class / id. Your third '.ted' div is the fourth child of your body.
To get the behavior you want, add a selector to your index call: Fiddle
$('.ted').click(function() {
alert($(this).index(".ted"));
});
When you pass a selector into index, it tells jQuery to look for the element in that set. If you don't, it looks to see where it is relative to all of its sibling elements.
Or alternately, remember the list of ted elements and then invert things: Fiddle
var teds = $(".ted");
teds.click(function() {
alert(teds.index(this));
});
When you pass an element into index, that tells jQuery to look for that element in the set.
the index is the child within the parent. If you want to enumerate the .ted elements try this:
$('.ted').each( function( i, a ){
$(a).click( function(){
alert( i ); // <- should be 0, 1 or 2.
} );
} );

find index of child using jQuery?

If I have an html structure like:
<div id="parent">
<div class="child first">
<div class="sub-child"></div>
</div>
<div class="child second">
<div class="sub-child"></div>
</div>
<div class="child third">
<div class="sub-child"></div>
</div>
</div>
and I have a click handler defined through ($('#parent.child')).click() and then I click on the div with the class of second (first, second, third classes have simply been added to make demo clearer) is there a simple way to get the number 1 as it is the second child? (0 based index)?
Something like $(this).index
Just have a look at the jQuery API. The method you suggest, index, is exactly right:
$('#parent .child').click(function() {
var index = $(this).index();
});
From the docs:
If no argument is passed to the .index() method, the return value is
an integer indicating the position of the first element within the
jQuery object relative to its sibling elements.
Also note that I've changed the selector slightly from your example. I'm guessing that was just a typo in your question though. #parent.child will look for an element with ID "parent" and a class of "child", but you actually want #parent .child (note the space) to find elements with class "child" that are descendants of an element with ID "parent".
The index() method can be used for getting the position of an element inside a collection. In basic circumstances, $(this).index() should work.
But with more specific collections, you can get the position with collection.index(item). Imagine adding something simple into your #parent that should not be counted when measuring index() (a span, img, anything). With the simple method, your code is likely to break, but with the specific method, it won't.
Something like this should work for you:
var $children = $('#parent .child').click(function​ () {
console.log($children.index(this));
});​
jsFiddle Demo

Can anyone explain this bizarre behavior in jQuery next?

It works:
<div class="xpav">
Create
</div>
<div class="apr" style="display: none;">
sometext
</div>
<script>
$('.xpav').click(function() {
$(this).next(".apr").slideDown("fast");
})
</script>
It doesn't:
<div class="xpav">
Create
</div>
<br />
<div class="apr" style="display: none;">
sometext
</div>
<script>
$('.xpav').click(function() {
$(this).next(".apr").slideDown("fast");
})
</script>
Why breaks it?
.next() only looks at the element that comes after the given element, then checks that element against the selector if it's provided. In your second example, since the br is there and doesn't have the apr class, it isn't picked up. From the API docs:
Description: Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector.
Your second example requires the use of .nextAll() instead to search through all the next siblings:
$('.xpav').click(function() {
$(this).nextAll(".apr").slideDown("fast");
});
To pick up only the first .apr that's matched, use .eq(0):
$('.xpav').click(function() {
$(this).nextAll(".apr").eq(0).slideDown("fast");
});
under my impression next() only works if the sibling objuect is the same DOM tage,
what does work is:
$('.xpav').click(function() {
console.log($(this).next(".apr"));
$(this).siblings(".apr").slideDown("fast");
})
It's exactly that what the documentations says: "Description: Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector."
http://api.jquery.com/next/
Because next() takes you to the immediate next DOM element which is <br />. Why not use this:
$(".apr").slideDown("fast");
Simply because you are using the next() method in your code. The next DOM element from $('.xpav') in the second version of your code is a <br />, and since that doesn't match the filter, it doesn't slide anything down!
If you want it to work, you should consider using nextAll() instead of next(), as the latter ONLY gets the very next DOM element, where the former gets all siblings that are after itself in the DOM.

Categories