jquery selector executed on DOM sub-tree (as in backbone) - javascript

Be default, jQuery's object $ allows you to run selectors over entire DOM tree. However, Backbone (which relies on jQuery) allows you to run the selector not on entire (global) DOM, $, but also on local backbone view (this.$ in backbone views). It's just faster, since we don't traverse entire DOM tree, but just its part.
The question is: how to achieve that in pure jQuery (no backbone)? A code example would be appreciated.

You use find:
$(someElement).find("selector").doSomething();
There's also a likely-to-be-deprecated-at-some-stage form you'll sometimes see people using that looks like this:
$("selector", someElement).doSomething();
...but literally all jQuery does with that is turn around and call find.
Example looking within a div for a span with a given class:
// Get the div
var div = $("#the-div");
// Find the span within it, turn it green
div.find(".foo").css("color", "green");
<div id="the-div">
<span>Not this one.</span>
<span class="foo">This one.</span>
</div>
<div>
<span>Not this one.</span>
<span class="foo">Not this one either, despite it having the class; it's in the wrong div.</span>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Related

Find the first id of any descendant using jQuery

For draggable divs in JS on my page, I want to store the last location in local storage so that when a user refreshes, the draggable elements on the page stay put.
My HTML is in general like this:
<div id="some_id" class="draggable">
<p>I am a draggable thing.</p>
</div>
I then use the id of the div as a key in local storage so that having multiple draggable objects on the page doesn't result in them all being given the same position on refresh.
However, templates like this are sometimes used inside a template which handles visibility, so sometimes they'll be like this:
<div class="visibility_container draggable">
<button class="close_button">Close</button>
<div id="some_id">
<p>I am a draggable thing.</p>
</div>
</div>
Note that the draggable class is added programmatically each time.
These templates may vary but will never have ids within them – they'd be pretty terrible templates if they did – so I only need to find the first descendant element which has an id and use the value of that id as my local storage key.
How can I find the nearest element with JS? I'm aware that jQuery has a .closest() method which finds the nearest ancestor – I need to go in the opposite direction. I'm also aware of jQuery's .find() which can find me all descendants matching a selector, but I'm unsure I can guarantee the order in which jQuery returns these children as the API docs were not clear on that point.
I'm also aware of jQuery's .find() which can find me all descendants matching a selector, but I'm unsure I can guarantee the order in which jQuery returns these children as the API docs were not clear on that point.
find lists elements in document order (aka "DOM order") (and you're right, I'm surprised not to see a clear statement of that in the docs). "Document order" is a well-defined DOM term, it means a depth-first search of the descendant elements. Or put it another way: The one whose text is first in the markup.
So for instance:
<div id="container">
<div>
<div>
<div id="one"></div>
</div>
<div id="two"></div>
</div>
...then
console.log($("#container").find("[id]").first().attr("id"));
...will log one, not two.
This document order thing is common across most of the jQuery API and DOM methods like querySelectorAll, getElementsByTagName, and such. I'm not having any luck finding a clear statement of it in the jQuery documentation, though, which seems like an oversight. The closest I've found so far is a bit documenting an exception to that (e.g., saying here that "The second and third...create a jQuery object using one or more DOM elements that were already selected in some other way...unlike most other multi-element jQuery operations, the elements are not sorted in DOM order." [my emphasis].) The multiple selector docs also point out that the results will be in document order (not the order of the selectors).

Jquery remove function follow up

I submitted this question last week:
chrome not working with jquery remove
and was able to resolve it (stupidity on my part really), however my example was very simple. Currently I'm trying to use .remove to eliminate a complete div from a page before sending an array of inputs to an ajax function. However, I am not able to get .remove to work at all.
Here's my latest try:
http://jsfiddle.net/CJ2r9/2/
I get function not defined on the jsfiddle on multiple browsers. On my application I get absolutely no errors, but nothing works either.
I'm relatively new to javascript scopes, so if the problem is scope-wise then please let me know how I'm screwing up.
I have also tried using the .on jquery function, but it's a bit more confusing considering my div ids are dynamically loaded from the server (jstl, spring MVC, etc). If that's a solution please let me know how I can get on the right track.
Thank you!
The two problems in your jsFiddle are:
Scope: removeElem is not in global scope, since you left the default configuration option to execute the code on DOM ready. You can change it to "no wrap" to make the funciton global.
The elements you want to remove don't exist. The div elements have IDs like "removeXXXp" and in your event handlers you pass "removeXXXs".
Here is an other, simpler solution (in my opinion) for element removal. Given your markup:
<div class="scheduleSet" id="remove315p">
<!-- ... -->
Remove
</div>
You can use .on like so:
$('.schduleSet a.optionHide').on('click', function() {
// traverses up the DOM tree and finds the enclosing .schduleSet element
$(this).closest('.scheduleSet').remove();
});
You don't even need IDs at all.
I made a simple fiddle, the inline onclick doesn't see the function defined in javascript so I get a ReferenceError: myRemove is not defined.
By adding the listener in js, .remove() works fine.
Sorry I don't know what causes the difference in behavior though.
Test it out: http://jsfiddle.net/xTv5M/1/
// HTML5
<div id="removeme">foo bar</div>
<button onclick="myRemove('removeme')">Go</button><br>
<div id="removeMe2">foo bar</div>
<button id="go2">Go Again</button>
// js
function myRemove(name){
$('#'+name).remove()
};
$('#go2').click(function(){ myRemove('removeMe2') });
I see that you are already using jquery. Why dont you do it this way:
<div id="foo">This needs to be removed</div>
Remove
function removeElem(element){
$('#'+element).remove();
}
$(function(){
$("#remove").click(function(){
removeElem($(this).data('remove'));
});
})
Fiddle here: http://jsfiddle.net/vLgpk/
They way this works is, using data-remove (can be anything like data-xyz btw), binds the remove link with the div. You can then read this binding later when remove is clicked.
If you are new to jQuery, and wondering what data-remove is, its just custom attribute that you can add to you code which can be later retrieved using the data() call on the element. Many great frameworks like Bootstrap use this approach.
Advantage of using this approach in my opinion is you can have the remove links anywhere in your UI and they don't need to be related structurally to your divs by siting inside them.

Performance of jQuery selectors

HTML markup:
<div>
<a id="foo"> </a>
</div>
jQuery:
$('div').each(function(){
$('#foo', this).dosmth(); // 1
$('#foo').dosmth(); // 2
});
Which method would be faster to run dosmth?
Since we're getting a variety of answers, hopefully here's some clarity (check the examples here):
The fastest - There's no need to loop. Skip the $("div").each part and just do $("#foo"). foo is an ID, and thus lookup is instantaneous.
Middling - $("#foo") in a loop. Note that you also don't want this because it will execute the function for every div on the page (and for this reason on a larger document with a lot of divs this would be the slowest).
Slowest - $("#foo", this). The context node doesn't help in the first place, and then consider that jQuery will first build a jQuery object out of this and turn it into $(this).find("#foo"). That's all unnecessary, of course.
Bottom line: in most cases (e.g. sometimes when confirming that an ID is in one context and not another) context nodes are unnecessary with ID lookup.
Here are some resources from the jQuery source:
Handling for most of the cases here - note that $("#id") is singled out for handling as document.getElementById
find - what happens when you pass a context
Since an #id should be unique in the DOM your markup will be invalid (I am assuming more than one <div/> based upon using .each())
Change the id to a class and use the following:
<div>
<a class="foo"> </a>
</div>
<div>
<a class="foo"> </a>
</div>
And the script
$('div').each(function(){
$('.foo', this).dosmth(); //or $(this).find(".foo");
});
But if you only have one element with an id of foo selecting by id will be the fastest, plus you can drop the need for using .each()
$('#foo').dosmth(); //or document.getElementById("foo");
jquery selectors by id only is the fastest way to search because it uses getElementbyId in javascript.
so this one is the fastest:
$('#foo').dosmth();
if you use a context like:
$('#foo', this).dosmth();
it is translated into:
$(this).find('#foo').dosmth();
so that will make another useless operation because your #foo is unique
Regards,
Max
$('#foo', this).dosmth();
This will search within the context of the div and not the whole DOM, which will make the selector faster. This only makes sense to use when the DOM is large, otherwise, just use the normal selector: $('#foo').dosmth();
If you're using an id there's only ever going to be one. So you can just do:
$('a#foo').dosmth();
You don't need to use each() to go through each div and get all the a#foo's out of it. That WILL waste time, creating loops for no reason. Instead use:
$('a#foo').each(function(){ ... });
or even just:
$('a#foo').dosmth();
You can also do $('div a#foo').dosmth(); if you want.
Please read the discussion below regarding this answer or check Bryan answer above about the differences in speed of the selectors.
I would go with
$('a#foo', this).dosmth();
Update But instead of retrieving all the divs before, I would check for
only the desired one at the first time
like this
$('div a#foo').each(function(){
}

browsing through nodes

this is what an html structure of the webpage looks like:
<body>
<form>
<input type='file'/>
</form>
<div id='list'>
<div>value here<input id='delete' type='button'/></div>
</div>
</body>
i have found javascript code that triggers on 'delete' button click and removes input 'file' element. it uses this piece of code where element is input 'file' mentioned above:
deleteButton.onclick=function(){this.parentNode.element.parentNode.removeChild(
this.parentNode.element );}
i am trying to understand logic(rules) behind 'this.parentNode.element' ? why not accessing element directly 'element.parentNode.remove...'
many thanks
i am trying to understand logic(rules) behind 'this.parentNode.element' ?
There's no element property on the Node, Element, HTMLElement, or HTMLDivElement interfaces. So my guess would be that elsewhere in that code, you'll find something that's explicitly adding that property to the element instance of the div containing the button. You can do that, add arbitrary properties to element instances. These are frequently called "expando" properties and should be done very, very, very carefully.
Not the answer to the question, just opinion. It's better avoid constructions like
this.parentNode.element.parentNode
Because in case when you change your DOM structure, you will need rewrite you JS. So I think it's better to give id attributes to tags, and use next construction to get DOM element:
document.getElementById('element_id')
or if you will use some js framework (like jQuery) you can use even easier construction to get DOM element
$("#ement_id")
Ok, "removeChild" is a strange method, and quite probably, ill-conceived. It should look like:
<div>value here<input id='deleteMe' type='button'/></div>
var node = document.getElementById('deleteMe');
node.remove(); // <--- does not exist, but sure would be nice!!!
No, instead we have to do these shenanigans:
var node = document.getElementById('deleteMe');
node.parentNode.removeChild(node); // verbose! Convoluted!
We have to get the node's parent, call the method, then refer to the node again. This doesn't look like any other DOM methods as far as I recall. The good news is you can make it happen all in one line, chained, like a jQuery method.
You are best served to start over or copy somebody else's code. The use of "this" means it was within an object (or class), referring to other methods or properties within that object. You should stick to non-object variables and functions for now.
Hope that helps.

Getting text from a paragraph in jquery

This might be a very simple thing in jquery but I am not able to figure it out. My html document has the following structure
<div class="body">
<p>This is the text I want to extract</p>
</div>
I tried this
$("body").find("a p").text()
but this does not seem to be working for me. I am able to get the paragraph object but not the text. I tested it with console.log with no use.
What you have should be working (you can test it here), make sure you're running it when the DOM is ready though, like this:
$(function() {
alert($("body").find("a p").text()); //or just $("a p").text()
});
If it runs earlier, the elements may not be ready, and your selector won't find any matches.
If you want to select the class body make sure to use ".body" instead of "body" (which would select the <body> element). Here's a version using the .class selector:
$(function() {
alert($(".body a p").text());
});
the .html() function retrieves a nodes inner html.
$('.body a p').html();
should do the trick
Not sure if this would cause a problem, but you have invalid markup. From "The global structure of an HTML document" by the W3C
Generally, block-level elements may contain inline elements and other block-level elements. Generally, inline elements may contain only data and other inline elements. Inherent in this structural distinction is the idea that block elements create "larger" structures than inline elements.
a elements are supposed to be contained by block elements like p, not the other way around.
here is your paragraph element in html or php file which is id assign tt
<p id="tt">ALert Message </p>
in in jquery file to get the text of your paragraph with tt id can be
var tt = $("#tt").text();
alert(tt);
working fine for jquery-3.1.1.js

Categories