Why does function getElementsByClassName() work on javascript objects, but "getElementById" kick back "not a function"?
var divBox= makeDivBox(divParams);
var divContents = divBox.getElementById("divID");
errors : divBox.getElementById is not a function
But :
var divContents = divBox.getElementsByClassName("divClass")[0];
has no issue. Why?
edit: see similar courtesy of #rajuGT
You appear to have a couple issues.
divBox.getElementById("divID"); doesn't work because getElementById() is only a method on the document object. It is not a method on other types of objects. So, the divBox element does not have that method. You could use document.getElementById("divID") instead if there was only one divID in the entire document and if divBox was already inserted into the document.
var divContents = divBox.getElementsByClassName("divClass")[0]; works because .getElementsByClassName() is a method on all DOM objects so it works when you call it on divBox.
You call getElementById() like this document.getElementById("someID").
If you want to find something in a particular part of the subtree, you can use element.querySelectorAll("#someID") or if you want to have more than one object with a given identifier, then you can use a class name and use functions that find objects with a given class name.
As to your specific questions:
divBox.getElementById is not a function
That is because geetElementById() is only a method on the document object and divBox is not a document object so it does not have that method, therefore you get the error you are seeing.
Why does this have no issue:?
var divContents = divBox.getElementsByClassName("divClass")[0];
That is apparently because divClass is a class name, not an id value and all HTML elements contain the getElementsByClassName() method so you can call it on divBox just fine.
It is because the id should be unique to the page/document.
So calling from the document and from the element should be same always. Hence providing the method for other DOM nodes is not useful at all and hence the getElementById is not available/added to the other DOM elements.
where as getElementsByClassName returns all DOM elements for the given className when called on document node. If called with any other DOM element, only child nodes which have the given className DOM nodes will be returned. Here, the behavior is different compared to the getElementById, hence this method is available to all DOM nodes.
Related
When I add a class on the following object, everything is fine:
$('.select').on('click', function() {
$(this).addClass('active');
});
But when I try to add a class to a child, I get an error:
$('.select').on('click', function() {
$(this).find('.list')[0].addClass('active');
});
From my research I've learned that certain objects have specific methods that can be called on them. So there must be a difference between
$(this)
and
$(this).find('.list')[0]
But I can't figure out what the difference would be, and I don't know how to find that out.
The difference is that $(this)is a jquery object, while $(this).find('.list')[0] is a DOM element, and doesn't have functions and methodsprovided by jQuery.
Because calling $(this).find('.list') will give you a nodeList and when you call [0] you will get the first node object from this list, and a node or a DOM element is different from a jquery object, as jQuery wraps a DOM elemnt with its utility methods and attributes.
So what you need to do is to convert this DOM element to a jQuery object so you can call jQuery methods on it:
$($(this).find('.list')[0])
$(this).find('.list')[0] returns a dom element from the jQuery object.
Elements don't have an addClass() method and you should be seeing an error in browser console telling you that
If you want the first one you can use first() or eq()
$(this).find('.list').first().addClass('active');
// OR
$(this).find('.list:first').addClass('active');
// OR
$(this).find('.list').eq(0).addClass('active');
What is the type of the variable "element" in this snippet?
I thought it is a number (an ID or something), but now, I have no idea.
The code works, but I don't understand, why the var element can be used in a for cycle, like an array. Is there any explanation about this?
<script type="text/javascript">
function showAtrributes() {
var element = document.getElementById("videos");
var listAttributes = "";
for(var attribute in element) {
var valueOfAtrrib = element.getAttribute(attribute);
listAttributes = listAttributes + attribute + ": " + valueOfAttrib + "\n";
}
alert(listAttributes);
}
</script>
The getElementById() method returns the element that has the ID
attribute with the specified value.
[....]
Returns null if no elements with the specified ID exists.
So it returns an HTMLElement Object
source
What is the return type of document.getElementById()
Element. It returns a reference to the actual object for the element in the DOM (or null if none was found with that id). Details:
Spec for Element
Spec for getElementById
Element on MDN
getElementById on MDN
I thought it is a number (an ID or something)
No, that's "video" (the string you used to look it up). It's also accessible from the id property of the Element object.
The code works, but I don't understand, why the var element can be used in a for cycle, like an array.
for-in isn't primarily for use on arrays, it's for use on objects. The only reason it works on arrays is that arrays are objects. (See this question's answers and this page on MDN for more on that.) DOM elements are objects, so you can loop through their enumerable properties via for-in.
The return type of document.getElementById() is Element Object or null. Please Refer the following link from MDN:
It looks like you are really questioning why the for loop works, not what kind of object getElementById returns. Read this article:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
The for( var in ....) syntax causes Javascript to iterate over the properties of the object specified by ....
The return type can be anything that the programmer of a Web Browser defines to the JS VM library used, to create a specific implementation of Javascript. For instance, the webcwebbrowser which uses SpiderMonkey returns a JSObject of HTMLElement JSClass which it gets by calling CreateJSObject on the underlying internal HTMLElement object. The JSObject is the internal VM library representation of objects visible to JS scripts, such as a HTMLElement. A HTMLElement in a script is actually accessing a JSObject logically instantiated from the HTMLElement JSClass, where JSObject and JSClasses are C++ classes. The HTMLElement JSObject also has a corresponding C++ native marshalled object of class HTMLElement.
I know that Enumeration by ClassName can be used for multiple objects, and Enumeration by ID can be used for particular objects.
But is there any other specific difference between the two methods?
getElementsByName:
This method returns the collection of elements whose name value is
given by elementName (The name attribute value for an element.)
This method is case sensitive.
getElementById:
Returns the Element whose ID is given by elementId.
If no such element exists, returns null.
Note: Behavior is not defined if there are more than one element has the same ID.
You may consider also Performance.
Referring to this link, it looks like getElementByClassName is faster.
But it really depends on the specific page you are on, and the browser engine.
The reason I ask is because I'm thinking of storing a bunch of DOM nodes in this huge and multi-dimensional array I have.
Cost: takes up space in memory. The question is how much space, and that depends on whether I'm getting references or actual DOM nodes.
Benefits: 1) It'll make my code a lot simpler. 2) I could avoid traversing and instead just reference the DOM node from my array.
Thoughts?
From jQuery site:
… jQuery() — which can also be written as $() — searches through the
DOM for any elements that match the provided selector and creates a
new jQuery object that references these elements
jQuery Documentation
jQuery returns the actual DOM Node. It's why you will find yourself writing $(this) most of the time. This is because you want to wrap your node in jQuery to be able to use some jQuery methods. However, it's recommended (almost in the guidelines) to cache your DOM nodes through references. For example,
var div = $('div');
div.dosomeMethod();
div.append();
This ensures that you are not traversing the entire DOM tree (the expensive DOM part) whenever you're trying to access some element. Whenever you do updates, ensure you're doing them as a batch.
in this example I show how to clone existing DOM element to object in memory, also create object in memory without pushing it to body, created collection objects, appended elements from collection to body and keep referenced objects, removed from body.
and so many operations...
var $newElement1 = $(selector).clone(); // create new element from existing and store in memory
var $newElement2 = $('<div>blabla</div>'); // create new element from html code and store in memory
var elements = [];
elements.push($newElement1);
elements.push($newElement2);
for(var i in elements) {
elements[i].appendTo($('body'));
}
$newElement1.remove(); // will remove it from body
** but I recommend You to use frameworks like: angularjs, reactjs, emberjs to save Your time
A reference to the object is returned. See here: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
This answer is wrong, please see the comments below.
Document.getElementById() and methods or wrappers that rely on it return a reference.
Likewise for Document.querySelector().
This all stems from the DOM4 spec, which states that (emphasis mine):
A collection is an object that represents a lists of DOM nodes. A collection can be either live or static. Unless otherwise stated, a collection must be live.
From a programming point of view this notion is easy to understand, you waste less memory and no time is spent copying things around, leading to faster execution.
However, for Document.querySelectorAll() we have an interesting case:
The NodeList object returned by the querySelectorAll() method must be static.
This means, as MDN puts it, that Document.querySelectorAll()
Returns a non-live NodeList of all the matching element nodes.
This means that the returned set is not a set of references to the original nodes, but instead to a set of nodes that represent the nodes at the time the query was executed. This means that a copy of all the matching nodes had to be made and you're no longer working with references to the live nodes.
In short:
Some JavaScript methods return references to the DOM Node.
Some JavaScript methods return array-like objects that contain references to the DOM Nodes. These objects aren't very big(?).
jQuery returns a jQuery object that contains references to the DOM Node(s). These jQuery objects could get quite big, depending on how many chained calls are made.
The actual DOM nodes are never actually returned "by value".
The size of the references themselves are small. Typically the size of a pointer.
JavaScript:
getElementById and querySelector(?) return references to the DOM Node.
getElementsByClassName and getElementsByTagName return live HTMLCollections.
getElementsByName returns a live NodeList.
getElementsByNameNS returns a live NodeList or a live HTMLCollection, depending on the browser.
querySelectorAll returns a non-live NodeList.
HTMLCollection and NodeList contain references to DOM nodes. They don't seem to be very big objects.
Live vs. Non-Live
From MDN:
In some cases, the NodeList is a live collection, which means that
changes in the DOM are reflected in the collection. For example,
Node.childNodes is live:
var parent = document.getElementById('parent');
var child_nodes = parent.childNodes;
console.log(child_nodes.length); // let's assume "2"
parent.appendChild(document.createElement('div'));
console.log(child_nodes.length); // should output "3"
In other cases,
the NodeList is a static collection, meaning any subsequent change in
the DOM does not affect the content of the collection.
document.querySelectorAll returns a static NodeList.
jQuery
From learn.jquery.com
A jQuery object is an array-like wrapper around one or more DOM elements. To get a reference to the actual DOM elements (instead of the jQuery object), you have two options. The first (and fastest) method is to use array notation:
$( "#foo" )[ 0 ]; // Equivalent to document.getElementById( "foo" )
The second method is to use the .get() function:
$( "#foo" ).get( 0 ); // Identical to above, only slower.
You can also call .get() without any arguments to retrieve a true array of DOM elements.
What's the jQuery equivalent for each():
$(".element").each(function(){
// do stuff
});
when attaching a function to a single element, like #element ?
You can always reference the jQuery object in a variable:
var $el = $('#element');
...then manipulate it.
$el.doSomething(); // call some jQuery methods from the cached object
$el.doSomethingElse();
If the reason you wanted .each() was to reference the DOM element as this, you don't really need the this keyword to do it, you can simply grab the DOM element out of the jQuery object.
var element = $('#element')[0]; // both of these give you the DOM element
var element = $('#element').get(0); // at index 0
The two of these are equivalent, and will retrieve the DOM element that would be referenced as this in the .each().
alert( element.tagName ); // alert the tagName property of the DOM element
alert( element.id ); // alert the ID property of the DOM element
I'd note that it isn't necessarily bad to use each to iterate over a single element.
The benefits are that you have easy access to the DOM element, and you can do so in a new scope so you don't clutter the surrounding namespace with variables.
There are other ways to accomplish this as well. Take this example:
(function( $ ) {
// Inside here, "this" will refer to the DOM element,
// and the "$" parameter, will reference the jQuery library.
alert( this.tagName );
// Any variables you create inside will not pollute the surrounding
// namespace.
var someVariable = 'somevalue'; // is local to this function
}).call( $('#element')[0], jQuery );
To directly answer your question, .each() operates normally on element sets of any size including 1.
You can also omit the .each() call completely and just call jQuery methods on $('#element'). Remember that you can chain most if not all jQuery method calls as they return the jQuery object. This even works on multiple elements for the matter, depending on what the methods do.
$('#element').doSomething().doSomethingElse();
If you need to reference the object multiple times, make a variable:
var $elm = $('#element');
$elm.doSomething();
doSomethingElse($elm);
Use first().
each() matches all elements, while first() matches only the first.
There are other selectors too. When you use the id in the selector, you will only get one element. This is the main difference between .element and #element. The first is a class that can be assigned to many elements, while the second is an id that belongs to only (at most) one element.
You can still use each if only one (or 0) element is returned. Also, you can skip each altogether if you want to link an event. You use each when you want to execute a specific function for each element in the list of elements.
If there is only 1 element, you can access it normally using the selector.
$('#your_element').your_event(function() {
});
Behind the scenes, each is just a for loop that iterates through each element in the map returned by jQuery.
It is essentially† the same as:
var i, map = $('...selector...');
for (i = 0; i < map.length; i++)
{
someFunction(i, map[i]);
}
† There's more to it than this, involving calling the function in the context of the map element etc.
It's implementation is to provide a convenient way to call a function on each element in the selection.
Do you mean like $('#element').children().each()
supposing you have something like a ul with an id and you want the li each inside it?
If the intention is to call a (non-jQuery) function in a new scope I think using "each" still is a valid (and probably the most elegant) way and it stays true to the jQuery syntax although I agree to Alex, it feels wrong since it might have some overhead.
If you can change the syntax use $('#element')[0] as replacement for this (as already mentioned in the accepted answer).
Btw could someone with enough reputation please correct the comment of "zzzzBov" about the accepted answer?
$('#element')[0] and $('#element').get(0) ARE! the same, if you want the jQuery object use $('#element').first() or $('#element').eq(0)