<div id="parent">
<div id="child"></div>
</div>
<!-- script -->
<script type="text/javascript">
var $parent = $("#parent");
//$parent().dosomething()
// ... use $parent do something
//!!! now i want use child !!!
var $child = $parent.find("#child"); //method one
var $child = $("#child"); //method two
//$child().dosomething()
</script>
Question: method one or method two is better ??(hope explanation in detail ,thanks!)
waiting for your help
here is a breakdown of what would be fastest. It shows that the $parent.find method is about 50% slower than the direct selector method. That means that if you've got to do with ids at all, it's quite significantly faster to just use the selector on its own.
As elclanrs said, as each ID must be unique, it's more efficient to call directly the ID selector (method two) than calling the find() function. Moreover, the find() function will get all the descendants of each element in the current set of matched elements, filtered by a selector (in this case it wouldn't be a good idea cause you are requesting just one element, filtered by its ID, which once again, must be unique). Method one will be useful just if you need to get more than one element inside the parent div, like <li> selectors, elements of the same class, etc.
Related
I'm loading some HTML with jQuery asynchronously:
$.get(path, {}, function (data) {
var result = $(data);
var resultSelector = result.find(selector);
});
result is a valid HTML that contains my selector (in my specific case, "#UsersAndRolesResults").
I can see that it contains when I simply type result into the console, it's there exactly with the same ID, no typos or anything.
However, result.find(selector) returns 0 elements.
In my specific example, this is result:
And:
Why?
UPDATE: I can query for other elements that are inside #UsersAndRolesResults with their ID tag and they are returned correctly. I also cannot query any other top-level elements in the result. I think there is an issue with querying top-level elements inside the result.
UPDATE 2: Just try $('<div id="target"></div>').find("#target") and you will get 0 results, where you should obviously get the div.
No. This is not bug, this is behavior defined in jQuery.
find() is used to select the elements which are inside the element on which find is called. In your case, the element is not children of the selector, so find will not work.
Example:
<div id="container">
<div class="message">Hello World!</div>
<div>Bye World</div>
</div>
JavaScript:
$('#container').find('.message');
This will select the element having class message and which is inside the element having ID container.
But, if you use find, it'll return nothing i.e. empty array since there is no element #container inside #container.
$('#container').find('#container');
Your code is equivalent to this ^^^.
If you want, you can use filter. filter will go through each element and check if this matches the selector, if it then the element is added to the result set.
$('#container').filter('#container');
This'll give you complete element.
It seems to be a design decision with jQuery. Top-level elements in an AJAX result are not queried correctly with find. Interesting.
I've solved my problem with a workaround by creating a dummy div element, encapsulating my result inside that element, and then querying that dummy element. It worked:
var t = $("<div>")
t.append(result);
t.find("#UsersAndRolesResults"); //this one returned my object correctly
For a simple example, try:
$('<div id="target"></div>').find("#target");
You will get 0 results.
Try:
$('<div><div id="target"></div></div>').find("#target")
And you'll get the correct result.
Try this:
$.get(path, {}, function (data) {
var result = $($.parseHTML(data));
var resultSelector = result.find(selector);
});
Given
console.log($("<div id=target></div>").find("#target"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
.length would be 0 as expected.
You can use .closest() to search for both child elements and original jQuery object selector
console.log($("<div id=target></div>").closest("#target"));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I am writing a small library where I am in need of selecting a relative element to the targeted element through querySelector method.
For example:
HTML
<div class="target"></div>
<div class="relative"></div>
<!-- querySelector will select only this .target element -->
<div class="target"></div>
<div class="relative"></div>
<div class="target"></div>
<div class="relative"></div>
JavaScript
var target = document.querySelectorAll('.target')[1];
// Something like this which doesn't work actually
var relativeElement = target.querySelector('this + .relative');
In the above example, I am trying to select the .relative class element relative only to the .target element whose value is stored in target variable. No styles should apply to the other .relative class elements.
PS: the selectors can vary. So, I can't use JavaScript's predefined methods like previousElementSibling or nextElementSibling.
I don't need solution in jQuery or other JavaScript libraries.
Well it should be ideally:
var relativeElement = target.querySelector('.relative');
But this will actually try to select something inside the target element.
therefore this would only work if your html structure is something like:
<div class="target">
<div class="relative"></div>
</div>
Your best bet would probably in this case be to use nextElementSibling which I understand is difficult for you to use.
You cannot.
If you insist on using the querySelector of the subject element, the answers is there is no way.
The spec and MDN both says clearly that Element.querySelector must return "a descendant of the element on which it is invoked", and the object element you want does not meet this limitation.
You must go up and use other elements, e.g. document.querySelector, if you want to break out.
You can always override Element.prototype.querySelector to do your biddings, including implementing your own CSS engine that select whatever element you want in whatever syntax you want.
I didn't mention this because you will be breaking the assumption of a very important function, easily breaking other libraries and even normal code, or at best slowing them down.
target.querySelector('.relative');
By using querySelector on the target instead of document, you scope the DOM traversal to the target element.
It is not entirely clear from your explanation, but by related i assume you mean descendant?
To get all target elements you can use
document.querySelectorAll('.target')
And then iterate the result
I found a way which will work for my library.
I will replace "this " in the querySelector with a unique custom attribute value. Something like this:
Element.prototype.customQuerySelector = function(selector){
// Adding a custom attribute to refer for selector
this.setAttribute('data-unique-id', '1');
// Replace "this " string with custom attribute's value
// You can also add a unique class name instead of adding custom attribute
selector = selector.replace("this ", '[data-unique-id="1"] ');
// Get the relative element
var relativeElement = document.querySelector(selector);
// After getting the relative element, the added custom attribute is useless
// So, remove it
this.removeAttribute('data-unique-id');
// return the fetched element
return relativeElement;
}
var element = document.querySelectorAll('.target')[1];
var targetElement = element.customQuerySelector('this + .relative');
// Now, do anything with the fetched relative element
targetElement.style.color = "red";
Working Fiddle
I usually create variables for frequently reused DOM elements like this:
var $dom_element = $('#dom_element);
where this is my setup:
<div id="dom_element">
<div class="child_element">
<div class="child_element">
</div>
what I'm wondering is if I can mix this variable with a subselector to get child elements. I guess it would be something like this:
var $child_element = $($dom_element + ' .child_element);
And if so, is there any speed benefit to doing this versus just saying:
$('.child_element);
considering the fact that both of these elements might be deeply nested in a large site?
With
var $dom_element = $('#dom_element);
I would use the following to get the child elements
var $child_element = $dom_element.find(".child_element");//I prefer this one, it is easier to read.
or
var $child_element = $(".child_element", $dom_element);
From my research/reading, it appears that setting an element to a variable is best if you are going to reference it many times. That way jQuery does not have to search the DOM many times.
Regarding your selectors, you can get yourself into trouble when using a bare class as a child selector. What if you have multiple child nodes using that same class?
.find() works, as others have suggested. You could alternatively use .children():
var $kids = $dom_element.children('.child_element');
http://api.jquery.com/children/
The difference between .find() and .children() is that .children() will only look one level down the DOM tree. .find() will recursively run through all possible child nodes to match your selector.
My code looks like this, in closeup:
<h2>
<span class="stuff">[<a id="someid">stuff</a>]</span> <span class="moreStuff">Another test</span>
</h2>
I've found a way to select my a element, and attach an id to it. What I need to do now is select its parent <h2> element, but not the <span> element. How can I do that (JQuery allowed)?
Edit: when I retrieve the selected <a>s, I get an array of them (there's lots of these structures on my page). When I try to write myArray[someIndex].closest("h2"), it says that the element does not have a closest() method. How would I go about this?
One ways is to use the .parents() method of jQuery, with a selector. Something like this.
$("#someid").parents("h2");
Update:
You can use the .closest() method with a selector, to only get the closest parent that match the selector.
$("#someid").closest("h2");
Update 2:
It would be a bit more work to do it with plain JavaScript. Not sure if it is the most efficient, but one way would be to select the element with document.getElementById() and then get a reference to its parent through the parentNode property. Then you would have to check if it is an h2 element, and if not, look at that elements parent node, and so on.
You could check the jQuery source and see how they have implemented the closest method.
I just needed the same thing. here a vanilla javascript variant:
function findParent(startElement, tagName) {
let currentElm = startElement;
while (currentElm != document.body) {
if (currentElm.tagName.toLowerCase() == tagName.toLowerCase()) { return currentElm; }
currentElm = currentElm.parentElement;
}
return false;
}
The <h2> is not the parent of the <a> but it is an ancestor, use .closest() to select it
$("#someid").closest("h2");
try use .parent() for get exactly double or more level up the DOM tree.
$("#someid").parent().parent();
When I want to get, for example, the 3rd level parent of the element I must write $('#element').parent().parent().parent() Is there a more optimal method for this?
Since parents() returns the ancestor elements ordered from the closest to the outer ones, you can chain it into eq():
$('#element').parents().eq(0); // "Father".
$('#element').parents().eq(2); // "Great-grandfather".
Depends on your needs, if you know what parent your looking for you can use the .parents() selector.
E.G:
http://jsfiddle.net/HenryGarle/Kyp5g/2/
<div id="One">
<div id="Two">
<div id="Three">
<div id="Four">
</div>
</div>
</div>
</div>
var top = $("#Four").parents("#One");
alert($(top).html());
Example using index:
//First parent - 2 levels up from #Four
// I.e Selects div#One
var topTwo = $("#Four").parents().eq(2);
alert($(topTwo ).html());
You could give the target parent an id or class (e.g. myParent) and reference is with $('#element').parents(".myParent")
Didn't find any answer using closest()
and I think it's the most simple answer when you don't know how many levels up the required element is, so posting an answer:
You can use the closest() function combined with selectors to get the first element that matches when traversing upwards from the element:
('#element').closest('div') // returns the innermost 'div' in its parents
('#element').closest('.container') // returns innermost element with 'container' class among parents
('#element').closest('#foo') // returns the closest parent with id 'foo'
A faster way is to use javascript directly, eg.
var parent = $(innerdiv.get(0).parentNode.parentNode.parentNode);
This runs significantly faster on my browser than chaining jQuery .parent() calls.
See: http://jsperf.com/jquery-get-3rd-level-parent
It's simple. Just use
$(selector).parents().eq(0);
where 0 is the parent level (0 is parent, 1 is parent's parent etc)
Just add :eq() selector like this:
$("#element").parents(":eq(2)")
You just specify index which parent: 0 for immediate parent, 1 for grand-parent, ...
If you plan on reusing this functionality, the optimal solution is to make a jQuery plugin:
(function($){
$.fn.nthParent = function(n){
var $p = $(this);
while ( n-- >= 0 )
{
$p = $p.parent();
}
return $p;
};
}(jQuery));
Of course, you may want to extend it to allow for an optional selector and other such things.
One note: this uses a 0 based index for parents, so nthParent(0) is the same as calling parent(). If you'd rather have 1 based indexing, use n-- > 0
If you have a common parent div you can use parentsUntil() link
eg: $('#element').parentsUntil('.commonClass')
Advantage is that you need not to remember how many generation are there between this element and the common parent(defined by commonclass).
you can also use :
$(this).ancestors().eq(n)
ex: $(this).ancestors().eq(2) -> the parent of the parent of this.
using eq appears to grab the dynamic DOM whereas using .parent().parent() appears to grab the DOM that was initially loaded (if that is even possible).
I use them both on an element that has classes applied it to on onmouseover. eq shows the classes while .parent().parent() doesnt.
As parents() returns a list, this also works
$('#element').parents()[3];
You could use something like this:
(function($) {
$.fn.parentNth = function(n) {
var el = $(this);
for(var i = 0; i < n; i++)
el = el.parent();
return el;
};
})(jQuery);
alert($("#foo").parentNth(2).attr("id"));
http://jsfiddle.net/Xeon06/AsNUu/