I have a nested table structure like
<table>
<td id="first">
<div class="wrapper">
<input name=1>
</div>
<input name=2>
<table>
<td id="second">
<input name=3>
I have jQuery selection $("#first")
. I'd like to traverse and find()
all children <input>s
within this <td>
context, but not to descent into the nested <table>
s.
So I need a jQuery trick which
Will find()
all children elements of a certain element
Will descent n levels down in DOM tree
But will stop descending if certain a element (<table>
) is encountered, so that the selector doesn't select inputs of a nested tables (which will be handled separately)
There could be any number of nested <table>
levels, so the solution should work no matter how many parent <table>
or children <table>
are encountered within the scope of $("#first") <td>
or any other <td>
I checked other jQuery find until questions. They have answers, but seems like they do not fill the last criteria
I had a similar issue in this other question. I ended up finally figuring out a plugin on my own after going back and forth with some people trying to think of a find selector.
USAGE :
ExclusiveInputs = $('#first').findExclude('input','table');
// Find-like method which masks any descendant
// branches matching the Mask argument.
$.fn.findExclude = function( Selector, Mask, result){
// Default result to an empty jQuery object if not provided
var result = typeof result !== 'undefined' ?
result :
new jQuery();
// Iterate through all children, except those match Mask
this.children().each(function(){
var thisObject = jQuery( this );
if( thisObject.is( Selector ) )
result.push( this );
// Recursively seek children without Mask
if( !thisObject.is( Mask ) )
thisObject.findExclude( Selector, Mask, result );
});
return result;
}
(Condensed Version):
$.fn.findExclude = function( selector, mask, result )
{
var result = typeof result !== 'undefined' ? result : new jQuery();
this.children().each( function(){
var thisObject = jQuery( this );
if( thisObject.is( selector ) )
result.push( this );
if( !thisObject.is( mask ) )
thisObject.findExclude( selector, mask, result );
});
return result;
}
Update: Let's have another take at this.
Basically, you want to match all the <input>
elements that are descendants of #first
and that are not children of <td>
elements nested more than one level deep under #first
.
(I'm not sure about that last under #first
part, but implementing it allows us to support <td>
elements above #first
in the ancestor chain.)
Technically, the following selector alone should fulfill your requirements:
var inputs = $("#first td:not(#first td td) > input");
If this does not work in your browser (Sizzle should be up to the task I think, but complex selectors like :not()
are always tricky), you can delegate the processing to jQuery methods:
var inputs = $("#first td").not("#first td td").children("input");
Original answer follows:
You can use not() to exclude <input>
elements that have more than one <td>
ancestor:
var firstLevelCells = $("#first").find("input").not("td td input");
eh, i have a better idea..
var badTable = "table.bad"; //the one you want to avoid
var $goodInputs = $("#first").find('input').filter(function() {
return $(this).closest(badTable).length == 0;
});
this may or may not be fast enough for you. it depends on your DOM which you do not want to talk about ;)
if its slow, just write the code for your algorithm by hand. There isnt a selector shortcut.
I had a similar issue and was still challenged to do something without an extension loop or having the exact structure of the DOM. In my case I had already a reference to the element '#first' which if you don't we could get it for example with an each (even if it is only one object). The trick is to go back up the tree with parentsuntil and stop at your top element to see if there is any intermediate element satisfying the conditionn.
Using the shorthand lambda notation for the functions (as you can write in typescript) this would lead to this:
$('#first').each((idx, f) => $(f).find('input').filter((idx2, inp) => $(inp).parentsUntil(f, 'table').length == 0)
It might not be the most efficient way (as you first select everything to then throw away elements by mounting up the DOM-tree again, but it is compact and fairly generic.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With