So I tried to build a cache of the DOM:
var DOM = document.getElementsByTagName('*');
However, the DOM variable seems to be a dynamic reference, so that if I change an element in the DOM, the DOM variable changes as well.
I tried iterating through the DOM variable and using the cloneNode method to create a deep copy of each node. This works in that it does not change when I change the DOM. However, the problem is that a cloned node does not equal its original DOM node when you compare them with the === operator.
So to sum up, I'm looking to create a cache of the DOM that does not change but whose nodes are still equal to the original DOM nodes.
document.getElementsByTagName returns a "live" NodeList, which isn't what you think at all. When you access the list, the DOM is traversed (implementation may cache it) every time to get the result. This gives the illusion of the list being live.
document.getElementsByTagName("div") === document.getElementsByTagName("div")
//true
To do what you want, simply convert it to an array. DOM = [].slice.call(DOM)
You seem open to a jQuery solution, so:
$("*")
will return a jQuery object containing all the elements. It will not be updated as the DOM changes.
Or if you just want elements within the <body> (i.e., not <script> or <meta> elements, etc., from the <head>) then:
$("body *")
Being a jQuery object it will of course allow you to access jQuery methods, but you can also access the DOM elements directly with array notation:
var DOM = $("body *");
DOM.show(); // example jQuery method call
alert(DOM.length); // show count of elements in DOM
alert(DOM[4].value) // example of direct access to fifth DOM element
I prefer to use the following methodology:
https://gist.github.com/3841424#file-domcache-js
Or, you may replace the DOM object with a method in this implementation:
var myNS = {
myEventHandler: function(event){
this.DOM.$el.doSomething();
},
cacheDOM: function(){
return {
$el: $("#matrix")
};
},
initialize: function(){
this.DOM = this.cacheDOM();
}
};
Related
Ok so I finally have a code example to show this!
if ($('#Snowsports-row')[0].classList.contains("hidden") == false) {
$('#snowsports-only').removeClass("hidden")
}
The code works ONLY as written above, i.e., if the [0] were moved to the second line and removed from the first line, or if it were present/absent in both lines, it would fail.
I understand the output difference...
$('#Snowsports-row')
=> [<div>...]
$('#Snowsports-row')[0]
=> <div>...
...but I'm not understanding under what circumstances you're OK to get an array of element(s) and in which you need to tease out the exact element.
THANKS FOR ALL ANSWERS! Very clearly helped me to figure out that the problem may have been confusing JS/jQuery methods. Final version:
if ($('#Snowsports-row').hasClass("hidden") == false) {
$('#snowsports-only').removeClass("hidden")
}
The .classList method is not widely supported (not in MSIE 9.0 for example) so it's not portable, although where it exists it's fast.
Since every ID in a document is supposed to be unique, and since calling removeClass for a class that isn't present is harmless, just replace your entire call with:
$('#Snowsports-row').removeClass('hidden')
Or better yet, if that class means what I think it does, use .hide() and let jQuery do its job for you, potentially animation the transition in the process.
Alternatively, if you actually wanted to stick with using DOM and classList, you should use the .remove() method that classList already supports:
document.getElementById('#Snowsports-row').classList.remove('hidden')
although there's a minor disadvantage in that this code will crash if that element isn't found (since .getElementById will return null) whereas jQuery silently ignores calls made on empty selectors.
As for the meta-question - you use [n] if you want to access the single DOM element at position n within the jQuery object, as you've done when you use .classList.
You use .eq(n) to obtain a jQuery object representing that DOM element, e.g. if you want to apply jQuery methods to that (single) element.
If there's only a single element, or you want the jQuery method to apply to every matching element, just call the method directly on the selector, as I've done above.
First off, by using jQuery for what it's good at, you can replace this:
if ($('#Snowsports-row')[0].classList.contains("hidden") == false) {
$('#snowsports-only').removeClass("hidden")
}
with this:
$('#Snowsports-row').removeClass("hidden");
Your first block of code does the following:
With $('#Snowsports-row'), make a jQuery object that contains all DOM elements that match the select '#Snowsports-row'.
Then reach into the jQuery object with [0] and get the first DOM object in that jQuery object.
Then, use a property/method on that DOM element to determine if a class exists on that DOM element with your .classList.contains("hidden") reference.
Then, if you find that class, remove it.
A jQuery object contains inside it an array of DOM elements. If you call a method on the jQuery object itself like:
$('.tableRows').html("hello");
Then, you are asking jQuery to operate on ALL the DOM elements inside the jQuery object. You must use jQuery methods, not DOM methods.
If, on the other hand, you want to use a method such as .classList.contains(), that is only a method on an actual DOM element. That isn't a jQuery method. So, you have to reach inside of the jQuery object to get a specific DOM element out of it. That's what the [0] does. It reaches into the jQuery object and gets the first DOM element from its internal data structure. Once you have that DOM element, you can then use any DOM element methods on that DOM object.
FYI, if you ever want to get just the first DOM element from a jQuery object, but want the result to be a jQuery object, not just a DOM element, instead of [0], you can use .eq(0) like ths:
$('#Snowsports-row').eq(0).removeClass("hidden");
Now, in this specific case, this is never necessary because $('#Snowsports-row') cannot ever contain more than one DOM element because internally jQuery will only return the first matching DOM element when you are searching for a ID value (since there's never supposed to be more than one matching element with the same ID).
Just keep in mind that DOM element and a jQuery object are completely different types of objects with different methods on them. What makes it slightly confusing is that a jQuery object contains an internal list of DOM elements. But, if the object you are operating on is a jQuery object, then you can only call jQuery methods on it. If you reach into the jQuery object and pull out a DOM element, then you can only call DOM methods on it.
First of all, ids must be unique, so if you have more than one #Snowsports-only elements you can experience problems.
In your question, you are mixing jQuery code with pure Javascript code.
This:
if ($('#Snowsports-row')[0].classList.contains("hidden") {
...
}
Means that you get the first instance of #Snowsports-row (remember that is better if there is only one element with this id), but you get the DOM object (pure javascript) with the jQuery selector. You can do the same thing in jQuery like this:
$('#Snowsports-row').hasClass("hidden")
See more:
https://api.jquery.com/hasclass/
https://developer.mozilla.org/es/docs/Web/API/Element/classList
Sure, because you are operating over a list. Now, you're kind of mistaking the jQuery/javascript code. If you would like to use the same line twice you can basically drop jQuery altogether and write something like this:
var el = document.getElementById('Snowsports-row');
if (el.classList.contains('hidden')){
el.classList.remove('hidden');
}
In the first line you're selecting one specific DOM element, whereas in the second line you are selecting ALL elements in the DOM that fit that selector and removing the "hidden" class from all of them. Basically checking whether the element has a class can only be performed over an element (that's why you need to select the index, specifying a given element), but jQuery allows you to remove the class of every element inside a list (hence your second line)
Use jQuery's .eq() function. So:
var el = $('#Snowsports-row').eq(0);
if (el.hasClass("hidden")) {
$(el.removeClass("hidden")
}
There's also no harm in calling removeClass on an element that might not have that class... so:
$('#Snowsports-row').eq(0).removeClass('hidden');
I have several dynamically created elements on a page that I would like to POST the contents using jQuery to another page. The problem is, the elements created cannot be accessed via jQuery (only elements that existed on the page can be accessed using the $(#myElementID).
I've seen hundreds of posts using the live() and on() functions for accessing EVENTS, but no way to access any properties, values, innerHTML, etc, of the dynamically created ELEMENTS.
Is this simply not possible to do with jQuery?
$('#btnParseTable').click(function () {
var tblCustomPattern = $("#tblCustomPattern").innerHTML;
//This test alert yields "" because tblCustomPattern is undefined - yet FireBug clearly shows the table exists!
alert(tblCustomPattern);
var postData = { "method": "ParseTable", "tbl": tblCustomPattern };
$.post("tiler.aspx", postData, function (data) {
$("#test").html(data); //for testing
});
});
If not supported by jQuery, can this be done in JavaScript or is it not possible to post back information that is NOT an "INPUT" element?
This test alert yields "" because tblCustomPattern is undefined -
yet FireBug clearly shows the table exists!
You can assess dynamically created element after they being added to DOM. tblCustomPattern is undefined because jQuery object does not have attribute innerHTML You need DOM element to use innerHTML but the selector will return you jQuery object. You can use indexer [] or [get()][1] to get html element from jQuery object. It is zero-based index and you will get first element at zero index.
var tblCustomPattern = $("#tblCustomPattern")[0].innerHTML;
OR, using .get()
var tblCustomPattern = $("#tblCustomPattern").get(0).innerHTML;
OR using html()
var tblCustomPattern = $("#tblCustomPattern").html();
In this part of your code, you have a problem:
$("#tblCustomPattern").innerHTML;
The issue is that $("#tblCustomPattern") is a jQuery object. It is not a DOM object. The jQuery object does not have a property .innerHTML.
So, to fix your issue, you have several choices:
You can get the DOM element out of the jQuery object and then use the .innerHTML property on the DOM object directly.
You can use the jQuery method for this same functionality by called the jQuery .html() method.
You don't even really need jQuery for this at all, so you can just use plain JS.
So, any of these will work:
// get the first DOM object from the jQuery object
// two different methods for doing that
var tblCustomPattern = $("#tblCustomPattern")[0].innerHTML;
var tblCustomPattern = $("#tblCustomPattern").get(0).innerHTML;
// use the jQuery method to get the HTML
var tblCustomPattern = $("#tblCustomPattern").html();
// use plain JS - fastest option
var tblCustomPattern = document.getElementById("tblCustomPattern").innerHTML;
Like
$(":input")
How do you return each object if there are multiple inputs? Maybe in somekind of array?
Also, is it possible to return the individual objects while using $(":input").after(x) ?
jQuery each
$('input').each(function () {
$(this); // A Single Input
})
Or
$('input')[0]; // HTMLElement Input
Alternatively, jQuery's .get:
supports a little more than [...], e.g. .get(-1) returns the last
element (which can be useful) - pimvdb
How to get length: $('input').length
$('input')
will select all inputs
If you wanted to do something to them...
$('input').each(function(){
$(this).css('background','red')
})
see this http://jsfiddle.net/jasongennaro/RczBh/
the jQuery factory function, jQuery(...selector...) or $(...selector...), returns a jQuery.init object, which is essentially a fancy array of elements.
the each function is a simple way to continue to chain function calls while iterating through the entire selection of elements.
The .each() method is designed to make DOM looping constructs concise and less error-prone. When called it iterates over the DOM elements that are part of the jQuery object. Each time the callback runs, it is passed the current loop iteration, beginning from 0. More importantly, the callback is fired in the context of the current DOM element, so the keyword this refers to the element.
The function parameter has two parameters function( index, element ), you could use i in place of index as it has the same basic effect. this will also refer to the element, so the second parameter is largely unnecessary unless you plan on executing a function within inner scope while retaining the reference to the element.
var vals=[];
$('input').each(function(index,element){
var $this, val;
$this = $(this);
val = $this.val();
vals.push(val);
...do more stuff...
});
console.log( vals );
$(":input") // Returns a collection of DOM elements at 0-based indices wrapped
// in an object that contains jQuery methods
$(":input").length // Is used to discover the quantity of elements matched.
$(":input").after('something') // Implicitly applies .after() to each element.
// Most jQuery methods work this way.
$(":input").each(function() { // Lets you operate on each element individually.
alert( this.nodeName ); // "this" will reference the current element.
});
"Also, is it possible to return the individual objects while using $(":input").after(x)"
If you mean you want a collection of the resulting elements created by .after(), it will depend upon what x is.
If it's a single element (not a text node), just do this:
var new_elems = $(":input").after(x).next();
This places the new element after each input, then uses the next()[docs] method to traverse to the next element sibling of each input, which should be the new element that was inserted.
Is this:
var contents = document.getElementById('contents');
The same as this:
var contents = $('#contents');
Given that jQuery is loaded?
Not exactly!!
document.getElementById('contents'); //returns a HTML DOM Object
var contents = $('#contents'); //returns a jQuery Object
In jQuery, to get the same result as document.getElementById, you can access the jQuery Object and get the first element in the object (Remember JavaScript objects act similar to associative arrays).
var contents = $('#contents')[0]; //returns a HTML DOM Object
No.
Calling document.getElementById('id') will return a raw DOM object.
Calling $('#id') will return a jQuery object that wraps the DOM object and provides jQuery methods.
Thus, you can only call jQuery methods like css() or animate() on the $() call.
You can also write $(document.getElementById('id')), which will return a jQuery object and is equivalent to $('#id').
You can get the underlying DOM object from a jQuery object by writing $('#id')[0].
Close, but not the same. They're getting the same element, but the jQuery version is wrapped in a jQuery object.
The equivalent would be this
var contents = $('#contents').get(0);
or this
var contents = $('#contents')[0];
These will pull the element out of the jQuery object.
A note on the difference in speed. Attach the following snipet to an onclick call:
function myfunc()
{
var timer = new Date();
for(var i = 0; i < 10000; i++)
{
//document.getElementById('myID');
$('#myID')[0];
}
console.log('timer: ' + (new Date() - timer));
}
Alternate commenting one out and then comment the other out. In my tests,
document.getElementbyId averaged about 35ms (fluctuating from 25ms up to 52ms on about 15 runs)
On the other hand, the
jQuery averaged about 200ms (ranging from 181ms to 222ms on about 15 runs).
From this simple test you can see that the jQuery took about 6 times as long.
Of course, that is over 10000 iterations so in a simpler situation I would probably use the jQuery for ease of use and all of the other cool things like .animate and .fadeTo. But yes, technically getElementById is quite a bit faster.
No. The first returns a DOM element, or null, whereas the second always returns a jQuery object. The jQuery object will be empty if no element with the id of contents was matched.
The DOM element returned by document.getElementById('contents') allows you to do things such as change the .innerHTML (or .value) etc, however you'll need to use jQuery methods on the jQuery Object.
var contents = $('#contents').get(0);
Is more equivilent, however if no element with the id of contents is matched, document.getElementById('contents') will return null, but $('#contents').get(0) will return undefined.
One benefit on using the jQuery object is that you won't get any errors if no elements were returned, as an object is always returned. However you will get errors if you try to perform operations on the null returned by document.getElementById
No, actually the same result would be:
$('#contents')[0]
jQuery does not know how many results would be returned from the query. What you get back is a special jQuery object which is a collection of all the controls that matched the query.
Part of what makes jQuery so convenient is that MOST methods called on this object that look like they are meant for one control, are actually in a loop called on all the members int he collection
When you use the [0] syntax you take the first element from the inner collection. At this point you get a DOM object
In case someone else hits this... Here's another difference:
If the id contains characters that are not supported by the HTML standard (see SO question here) then jQuery may not find it even if getElementById does.
This happened to me with an id containing "/" characters (ex: id="a/b/c"), using Chrome:
var contents = document.getElementById('a/b/c');
was able to find my element but:
var contents = $('#a/b/c');
did not.
Btw, the simple fix was to move that id to the name field. JQuery had no trouble finding the element using:
var contents = $('.myclass[name='a/b/c']);
var contents = document.getElementById('contents');
var contents = $('#contents');
The code snippets are not the same. first one returns a Element object (source).
The second one, jQuery equivalent will return a jQuery object containing a collection of either zero or one DOM element. (jQuery documentation). Internally jQuery uses document.getElementById() for efficiency.
In both the cases if more than one element found only the first element will be returned.
When checking the github project for jQuery I found following line snippets which seems to be using document.getElementById codes (https://github.com/jquery/jquery/blob/master/src/core/init.js line 68 onwards)
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[2] );
Just like most people have said, the main difference is the fact that it is wrapped in a jQuery object with the jQuery call vs the raw DOM object using straight JavaScript. The jQuery object will be able to do other jQuery functions with it of course but, if you just need to do simple DOM manipulation like basic styling or basic event handling, the straight JavaScript method is always a tad bit faster than jQuery since you don't have to load in an external library of code built on JavaScript. It saves an extra step.
One other difference: getElementById returns the first match, while $('#...') returns a collection of matches - yes, the same ID can be repeated in an HTML doc.
Further, getElementId is called from the document, while $('#...') can be called from a selector. So, in the code below, document.getElementById('content') will return the entire body but $('form #content')[0] will return inside of the form.
<body id="content">
<h1>Header!</h1>
<form>
<div id="content"> My Form </div>
</form>
</body>
It might seem odd to use duplicate IDs, but if you are using something like Wordpress, a template or plugin might use the same id as you use in the content. The selectivity of jQuery could help you out there.
All the answers are old today as of 2019 you can directly access id keyed filds in javascript simply try it
<p id="mytext"></p>
<script>mytext.innerText = 'Yes that works!'</script>
Online Demo!
- https://codepen.io/frank-dspeed/pen/mdywbre
jQuery is built over JavaScript. This means that it's just javascript anyway.
document.getElementById()
The document.getElementById() method returns the element that has the ID attribute with the specified value and Returns null if no elements with the specified ID exists.An ID should be unique within a page.
Jquery $()
Calling jQuery() or $() with an id selector as its argument will return a jQuery object containing a collection of either zero or one DOM element.Each id value must be used only once within a document. If more than one element has been assigned the same ID, queries that use that ID will only select the first matched element in the DOM.
All the answers above are correct. In case you want to see it in action, don't forget you have Console in a browser where you can see the actual result crystal clear :
I have an HTML :
<div id="contents"></div>
Go to console (cntrl+shift+c) and use these commands to see your result clearly
document.getElementById('contents')
>>> div#contents
$('#contents')
>>> [div#contents,
context: document,
selector: "#contents",
jquery: "1.10.1",
constructor: function,
init: function …]
As we can see, in the first case we got the tag itself (that is, strictly speaking, an HTMLDivElement object). In the latter we actually don’t have a plain object, but an array of objects. And as mentioned by other answers above, you can use the following command:
$('#contents')[0]
>>> div#contents
As far as I know document.getElementById('myId') will only look for HTML elements that are already in the document. Let's say I've created a new element via JS, but that I haven't appended it yet to the document body, is there's a way I can access this element by its id like I would normally do with getElementById?
var newElement = document.createElement('div');
newElement.id = 'myId';
// Without doing: document.body.appendChild(newElement);
var elmt = document.getElementById('myId'); // won't work
Is there a workaround for that?
(I must tell that I don't want to store any reference to this particular element, that's why I need to access it via its Id)
Thank you!
If it isn't part of the document, then you can't grab it using document.getElementById. getElementById does a DOM lookup, so the element must be in the tree to be found. If you create a floating DOM element, it merely exists in memory, and isn't accessible from the DOM. It has to be added to the DOM to be visible.
If you need to reference the element later, simply pass the reference to another function--all objects in JavaScript are passed by reference, so working on that floating DOM element from within another function modifies the original, not a copy.
For anyone stumbling upon this issue in or after 2019, here is an updated answer.
The accepted answer from Andrew Noyes is correct in that document.getElementById won't work unless the element exists in the document and the above code already contains a reference to the desired element anyway.
However, if you can't otherwise retrieve a direct reference to your desired element, consider using selectors. Selectors allow you to retrieve nodes that aren't necessarily in the DOM by using their relationship to other nodes, for example:
var child = document.createElement("div");
child.id = "my_id";
var parent = document.createElement("div");
parent.appendChild(child);
var child2 = parent.querySelector("#my_id");
getElementById is a method on the document object. It's not going to return anything not in the document.
On not storing a reference, huh? If you could magically pull it out of the air by id, then the air would be a reference to it.
If you've created it, just pass the object to other functions and access it directly?
function createDiv()
{
var newElement = document.createElement('div');
doWorkWithDiv(newElement);
}
function doWorkWithDiv(element)
{
element.className = 'newElementCSS';
element.innerHTML = 'Text inside newElement';
addToDoc(element);
}
function addToDoc(element)
{
document.body.appendChild(element);
}