jQuery .closest() returns multiple results within a custom jQuery plugin
Asked Answered
S

2

5

While hacking my free-time project I stumbled upon a puzzling jQuery behaviour.

I have a custom validation plugin written and working. In the plugin I wanted to implement some functionality using .closest() method. Strangely enough this method returns multiple elements.

Here is a sample code:

this.closest(".control-group")
$(this).closest(".control-group");

Both above code lines select all four elements with class "control-group". This code put inside my plugin works:

var element_ID = this.attr("id");
$("#" + element_ID).closest(".control-group")

Above selects the correct and only one element with "control-group" class.

I can't use this "hack" as not all elements that I want to validate have "id" property set, so it won't work in all cases.

Using jQuery 1.7.2 (seems to be latest stable). Any ideas why it's like that?

Stereogram answered 14/6, 2012 at 9:23 Comment(1)
try console.log(this.length)and see if this points to more than one elementBluff
D
6

this is a jQuery object that contains at least 4 DOM elements, and calling .closest on it will retrieve the closest .control-group elements for all of those.

this.attr("id") will retrieve the id of the first dom element in the jQuery object, so you could have just done $(this[0]).closest...

Dina answered 14/6, 2012 at 9:27 Comment(7)
In the context above this is a element being validated. According to the .closest() docs, it travels up in the DOM tree so it should search for the elements above this element and return element with "control-group" class which is "closest" to this. But it returns all elements from DOM tree.Stereogram
@Stereogram this is a jQuery object, otherwise you wouldn't be able to call this.closest() like that.Dina
I know it's already a jQuery object, the main question is why .closest() returns four elements when called this.closest() and only one when called like this $("#" + this.attr("id")).closest() (this is the correct behaviour).Stereogram
I already explained, this.attr("id") returns the id of the first element encapsulated by the jQuery object. So you now have a jQuery object with only one element, so calling .closest on that jQuery object will retrieve only 1 element at maximum. Calling .closest on a jQuery object and getting 4 elements as a result means that the jQuery object was holding at least 4 elements.Dina
.closest() by definition should return 0 or 1 element (this says the docs). Inside my custom plugin this should contain only one element, is this correct?Stereogram
@Stereogram no it returns 0 or 1 elements, per element held in the jQuery object. See jsfiddle.net/BQLs6 Hence, if you get 4 elements from calling something.closest, that something jQuery object must have held at least 4 elements.Dina
my mistake here, you were absolutely right! No it works perfectly.Stereogram
B
2

you may not have id's for all the elements but you do have this

instead of

var element_ID = this.attr("id");
$("#" + element_ID).closest(".control-group")

try

$(this).closest(".control-group")

Update

The jQuery site says:

Given a jQuery object that represents a set of DOM elements, the .closest() method searches through these elements and their ancestors in the DOM tree and constructs a new jQuery object from the matching elements. The .parents() and .closest() methods are similar in that they both traverse up the DOM tree. The differences between the two, though subtle, are significant:

.closest() : The returned jQuery object contains zero or one element

.parents() : The returned jQuery object contains zero, one, or multiple elements

here is the link: http://api.jquery.com/closest/

So your original question is maybe not answered

Bluff answered 14/6, 2012 at 9:26 Comment(3)
Sorry, forgot to mention that I already tried that and it does not work. I will add this to the question.Stereogram
Inside a jQuery plugin, this already is a jQuery object. No need to pass it to jQuery again. $(this) is the same as $($('some selector')).Interclavicle
The docs can seem contradictory as the descritipion says that constructs a new jQuery object from the matching elements. It can indeed return a jQuery object holding multiple elements if the target jQuery object was holding multiple elements. jsfiddle.net/BQLs6Dina

© 2022 - 2024 — McMap. All rights reserved.