How can I select the first "shallowest" input?
My current selection will be the div marked "selected".
I won't know how many levels down it will be.
<div class="selected"> <!-- already have this -->
<div class="unknown-number-of-wrapper-panels">
...
<div class="collection">
<div class="child">
<input type="text" value="2" /> <!-- don't want this -->
</div>
</div>
<input type="text" value="2" /> <!-- need this -->
<input type="text" value="2" />
...
</div>
</div>
It seems like find().first()
gives me the deepest one.
Edited for clarity. I need to find it based on the fact that it is shallower, not based on other unique attributes.
This might be like a reverse of closest()
?
If I understand your issue, you need to recursively check the child nodes for elements with that class.
function findShallowest( root, sel ) {
var children = root.children();
if( children.length ) {
var matching = children.filter( sel );
if( matching.length ) {
return matching.first();
} else {
return findShallowest( children, sel );
}
} else {
return null;
}
}
var selected = $('.selected');
findShallowest( selected, ':text' );
Example: http://jsfiddle.net/Qf2GM/
EDIT: Had forgotten a return statement, and had an ID selector instead of a class selector for the initial .selected
.
Or make it into your own custom plugin:
Example: http://jsfiddle.net/qX94u/
(function($) {
$.fn.findShallowest = function( sel) {
return findShallowest( this, sel );
};
function findShallowest(root, sel) {
var children = root.children();
if (children.length) {
var matching = children.filter(sel);
if (matching.length) {
return matching.first();
} else {
return findShallowest(children, sel);
}
} else {
return $();
}
}
})(jQuery);
var result = $('.selected').findShallowest( ':text' );
alert( result.val() );
You are after a breadth-first search rather than the depth-first search (which jQuery's find() uses). A quick google has found: http://plugins.jquery.com/project/closestChild
This could be used like this:
$(...).closestChild('input')
Just to golf this "plugin" a bit - Uses @user113716's technique, just reduced code size.
$.fn.findShallowest = function( selector ) {
var children = this.children(),
matching = children.filter( selector );
// return an empty set if there are no more children
if ( !children.length ) {
return children;
}
// if anything matches, return the first.
if ( matching.length ) {
return matching.first();
}
// check grand-children
return children.findShallowest( selector );
};
Try on jsFiddle
This is another approach. The idea is that you get the matching element with the least number of ancestors:
(function($) {
$.fn.nearest = function(selector) {
var $result = $();
this.each(function() {
var min = null,
mins = {};
$(this).find(selector).each(function() {
var n_parents = $(this).parents().length,
if(!mins[n_parents]) {
mins[n_parents] = this;
min = (min === null || n_parents < min) ? n_parents : min;
}
});
$result = $result.add(mins[min]);
});
return $result;
};
}(jQuery));
Usage:
$('selected').nearest('input');
DEMO
findShallowest
, as @patrick has it, might be a better method name ;)
If you don't know the class name of the bottom level element you can always use something like
$('.unknown-number-of-wrapper-panels').children().last();
Well given your markup, would the following work?
$('.selected div > input:first')