Is there a way to select a child DOM object by treating it as data member of its parent DOM object? Imagine I have this code:
<div id=div1>
<div id=innerdiv1></div>
<div id=innerdiv2></div>
</div>
<div id=div2>
<div id=innerdiv1></div>
<div id=innerdiv2></div>
</div>
This example won't work in real life because both pairs of child divs have the same id's (innerdiv1, innerdiv2), but that's exactly what bothers me about the "id" thing.
Is there some way in javascript to access a child element as a data member, something like document.getElementById('div1.innerdiv1'), which would return a different object from document.getElementById('div2.innerdiv1').
I can't stand that each id has to be unique throughout the document. It becomes a major issue when you have a lot of code and you accidentally use the same id twice. It makes for really nasty bugs that are difficult to squash.
You can use document.querySelector in modern browsers. document.getElementById is pretty much obsolete.
document.querySelector('#div1 #innerdiv1')
You can use classes for the inner divs instead of ids, which do not need to be unique.
The document object has a getElementById method, but the returned elements do not have this method, and it couldn't take a string that isn't exactly the id of an element [if that's what you want try a library, like jQuery or Pumbaa80's suggestion of document.querySelector].
In some browsers you can try:
document.getElementById('div1').getElementsByTagName('div')[0]
As a side note, try dropping these two html documents into html5.validator.nu or http://validator.w3.org/#validate_by_input
<!DOCTYPE html><head><title>t</title></head><body>
<div id=div1><div id=d1>one</div><div id=d2>two</div>three</div>
<div id=div2><div id=d1>four</div><div id=d2>five</div>six</div>
</body>
Now you can totally avoid using the same id twice by just using classes instead.
<!DOCTYPE html><head><title>t</title></head><body>
<div id=div1><div class=d1>one</div><div class=d2>two</div>three</div>
<div id=div2><div class=d1>four</div><div class=d2>five</div>six</div>
</body>
For the first one, you could use document.querySelector('#div2 #d1') or $('#div2 #d1')
but I don't think the result would be guaranteed across all browsers due to the fact that this should be equivalent to writing document.querySelector('#d1') which you can see returns the first occurring id that matches, or $('#d1') which returns both id matching elements in an array.
And for the second one you could use document.querySelector('#div2 .d1') or $('#div2 .d1') or the other statements for very similar results, except that your html is valid this time. You don't even have to have css that defines d1 and d2 and if you used an attribute like class="d1 mySubHeading" and class="d2 mySubHeading" you could style both with mySubHeading and leave d1 and d2 there purely for selection via these methods.
Related
Kind of a newbie to this but I have followed a totorial on a memory game as an attempt to understand the syntax of JS but am stuck on making the round result print in a instead of showing up as a alert
here is a codepen here.
how can I print round in a <span> <!-- result here--> </span> rather than like this alert("result")
How can I make it set to a span instead of being an alert?
Browsers parse HTML into a tree of objects called Document Object Model (DOM). Using JavaScript you can query the DOM to get individual nodes, and then change them.
To get your span, you would typically use document.getElementById or document.querySelector (there are other functions that can fetch collections of related nodes, like document.getElementsByClassName or document.querySelectorAll). The former identify nodes by the property named in the method name (ID, or class name, respectively); the latter ones use CSS selectors. (All of the getElement... functions can be replicated using the newer querySelector and querySelectorAll interface, though you have to know how to use CSS selectors. I almost never use getElement... functions any more.) There are also functions that use XPath, though this is a bit more advanced subject.
Once you have the node, you can change its content using e.g. .textContent or .innerHTML properties, the former being for plain text, the latter for HTML.
For example, if this is the only span on the page, this suffices:
document.querySelector('span').textContent = "Result";
<span></span>
If on the other hand you have more of them, you would need some way to target the correct one. I will also demonstrate how you can style it using HTML:
const node = document.querySelector('#result_goes_here');
node.innerHTML = "<strong>Result</strong> in bold!";
<span id="result_goes_here"></span>
If you are trying to add the result inside the HTML SPAN and not in the alert box. You can do it something like this:
document.getElementById("span_ID").innerHTML = the_variable_result_here;
Hope that helps!
For example, document.getElementsByClassName("whatever") returns a list of elements, and each element has an index (so the element x is the [3] in that list, for example).Do HTML elements save that index inside the element, somehow? Or they're 'unaware' of their position?
Example of the usage I'd do with that property:
You click an element with class "People", using event.target when onclick. So you want to know which position it has, in the 'People' list. Let's say it's event.target.classNameIndex. So once you know the index, you can do things in JavaScript.
Obviously the simple alternative I can think of this is simply picking event.target and searching it inside the getElementsByClassName list. Or simply giving IDs to all elements. But avoiding that would be nice.
Hope you understand my question. :)
No
The elements are generated either dynamically or statically and are independent from everything done with them after being displayed. There are pure javascript ways of obtaining the index of an element in a array-like structure but they will most likely depend on the use of a element.onClick function and pairing them with other elements via some sort of selector.
No, for lots of reasons.
First of all, you are doing a query on the internal DOM structure, and the DOM tree itself might change immediately after your query. Elements can be added, moved or removed.
Furthermore, two very different queries might have overlapping results. E.g. query 1 might return:
[ <div id="a">, <div id="b"> ]
While query 2 could return:
[ <div id="b">, <div id="c"> ]
(for simplicity I am representing the results as arrays)
In the above, how would the element <div id="b"> know its unique and unchanging "index", given the truly infinite amount of possible queries, not the mention the possibly variable DOM again?
What is the difference between these two syntaxes below-
document.object and document.getElementById().
I want to know when to use which syntax???
e.g.-
CODE1(Implementation with <form>)
<body onload="document.forms[1].innerHTML='hi';">//Alt: onload="document.getElementById('f1').innerHTML='hi';"
<form id=f1>
<input />
</form>
<form id=f2>
<input />
</form>
</body>
both the syntax in onload works the same way. But this doesn't work for the following-
CODE2(Implementation with <div>)
<body onload="document.getElementById('div1').innerHTML='hi';">//cannot use the syntax: onload="document.divs[1].innerHTML='hi';"
<div id=div1>hello</div>
<div id=div2>hello</div>
</body>
So definitely the syntax: document.object does not work with <div>-elements but works with <form>'-element. But **document.getElementById()`** works for both. So when should I use which one???
Someone please highlight the differences between the two syntaxes.
Thanx in advance...
document.forms is a very old method of accessing stuff, along with document.images and document.all, and possibly a few others that I don't remember.
The number one flaw in accessing document.forms[1] is simple: what if another form is added to the page, before the target one? Suddenly you have to search through all your code for references to anything, and change them.
This is where IDs come in. By only allowing one of each ID on a page, getElementById can accurately retrieve it, every time, without caring about what happens to the document in the meantime. The only change that matters is the element being removed altogether.
you can use document.object_name to find anchors, applets, embeds, forms, images, links, plugins.
to find HTML Elemets like div, span, etc. you have to use selectors. you can get this elements by element name, id, class, etc.
The easiest way to access the div in your example is via the "named access on window object" functionality (http://www.whatwg.org/specs/web-apps/current-work/#named-access-on-the-window-object):
Instead of
<body onload="document.getElementById('div1').innerHTML='hi';">
you can use
<body onload="div1.innerHTML='hi';">
Note that "div1" is a property of the window object, not of the document object.
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(){
}
It seems pretty common to want to let your javascript know a particular dom node corresponds to a record in the database. So, how do you do it?
One way I've seen that's pretty common is to use a class for the type and an id for the id:
<div class="thing" id="5">
<script> myThing = select(".thing#5") </script>
There's a slight html standards issue with this though -- if you have more than one type of record on the page, you may end up duplicating IDs. But that doesn't do anything bad, does it?
An alternative is to use data attributes:
<div data-thing-id="5">
<script> myThing = select("[data-thing-id=5]") </script>
This gets around the duplicate IDs problem, but it does mean you have to deal with attributes instead of IDs, which is sometimes more difficult. What do you guys think?
Note that an ID cannot start with a digit, so:
<div class="thing" id="5">
is invalid HTML. See What are valid values for the id attribute in HTML?
In your case, I would use ID's like thing5 or thing.5.
<div class="thing" id="myapp-thing-5"/>
// Get thing on the page for a particular ID
var myThing = select("#myapp-thing-5");
// Get ID for the first thing on the page
var thing_id = /myapp-thing-(\d+)/.exec ($('.thing')[0].id)[1];
You'll be giving up some control of the DOM
True, nothing will explode, but it's bad practice. If you put duplicate ids on the page you'll basically loose the ability to be sure about what you're getting when you try to access an element by its id.
var whoKnows = document.getElementById('duplicateId');
The behavior is actually different, depending on the browser. In any case, you can use classNames for duplicate values, and you'll be avoiding the problem altogether.
The browser will try to overlook faults in your markup, but things become messy and more difficult. The best thing to do is keep your markup valid. You can describe both the type of the element and its unique database id in a className. You could even use multiple classNames to differentiate between them. There are a lot of valid possibilities:
<div class="friend04"/>
<div class="featuredFriend04" />
or
<div class="friend friend04" />
<div class="featuredFriend friend04" />
or
<div class="friend objectId04" />
<div class="groupMember objectId04" />
or
<div class="friend objectId04" />
<div class="friend objectId04" id="featured" />
These are all completely legitimate & valid snippets of XHTML. Notice how, in the last snippet, that I've still got an id working for me, which is nice. Accessing elements by their id is very quick and easy, so you definitely want to be able to leverage it when you can.
You'll already spend enough of your time in javascript making sure that you've got the right values and types. Putting duplicate ids on the page will just make things harder for you. If you can find ways to write standards-compliant markup, it has many practical benefits.
IDs should be unique according to the standards and whilst most browsers don't barf when handed duplicate IDs it would not be a good idea to rely on that always being the case.
Making the ID unique by adding a type name to the ID would work but you need to ask why you need it. Giving an element an id is very useful when the element needs to be found, getElementById is very fast. The reason its fast it that most browsers will build an index of IDs as its loads the DOM. However if you have zillions of IDs that you never actually need to use in something like getElementById then you've incurred a cost that is never paid back.
I think you may find most of the time you want the object ID in an event fired by the element or one of its children. In which case I would use an additional attribute on the element and not the ID attribute.
I would leave class attribute to do what its meant to do and not overload it with identification duties.
Considering the fact that you can have multiple classes per element, couldn't you create a unique identifier as an additional class per element? That way, there could be more than one element with the same "id" without HTML ID attribute collisions.
<div class="thing myapp-thing-5" />
<div class="thing myapp-thing-668" />
<div class="thing myapp-thing-5" />
It would be easy to then find these nodes, and find their corresponding DB record with a little string manipulation.
In HTML5, you could do it like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
window.addEventListener("DOMContentLoaded", function() {
var thing5 = document.evaluate('//*[#data-thing="5"]',
document, null, XPathResult.FIRST_ORDERED_NODE_TYPE ,null);
alert(thing5.singleNodeValue.textContent);
}, false);
</script>
</head>
<body>
<div data-thing="5">test</div>
</body>
</html>
If you set non-standard properties, be sure to either set them programmatically (as everything will be legal that way) or go through the trouble of revising the dtd !-)
But I would use an ID with a meaningful word prepending the DB-id and then use .getElementById, as every necessary informtion is at hand ...
Non-standard attributes are fine, if you're using XHTML and take the time to extend the DTD you're using to cover the new attributes. Personally, I'd just use a more unique id, like some of the other people have suggested.
I don't like John Millikin's solution. It's gonna be performance-intensive on large datasets.
An optimization on his code could be replacing the regular expression with a call to substring() since the first few characters of the id-property are constant.
I'd go with matching class and then a specific id though.
Keeping track of your data via the DOM seems shaky to me; remember, those IDs are global variables, so if there's any chance somebody else's script can find its way onto your page, it's vulnerable. For best results, load your data into an object within an anonymous function and write the table (or the big nested list of DIVs) afterwards.