Consider the following code:
<html>
<head></head>
<body>
<div id='test' class='blah'>
<a href='http://somesite.com/' id='someLink'>click!</a>
</div>
</body>
</html>
So I just recently discovered that this creates a javascript object called someLink and I can for instance get the value of the href attribute with someLink.href. I tested this in the latest Chrome, FF and IE and it works.
First off, how long has this "feature" been around? I imagine probably a while, because I have known for years that IDs for html elements on a page must be unique, and if you do have more than one element sharing the same ID, the last one overwrites the previous one(s), and using for instance getElementById() will return the last one. But I never really understood why, but now, looking at it as a "this is creating an object" perspective, it makes sense. So, as far as being able to directly access it with the id-name-as-javascript object...how long has that been around? IE6 era? Earlier?
2nd...I guess this is more of a discussion point than question, but... IMO this doesn't seem like a very good "feature" to have... Isn't the whole point of having a DOM and wrapper functions like getElementById(), to give some organization and more importantly, cut down on namespace issues? I don't feel I should have to be worried about random html elements on a page overwriting my javascript variables (something that has recently happened, which is why I discovered this "feature"). Does anybody know why this is as it is, what's the logic behind it?
First off, how long has this "feature" been around?
It is a Microsoft-ism that cropped up around IE 4 if I remember correctly.
Some other browsers have added support for it in an effort to be compatible with badly written code that depends on it. Some may only support it in quirks mode.
this doesn't seem like a very good "feature" to have
Correct. Don't use it. :)
Yes, it's been around for a very long time, which is likely the only reason it exists. Removing such a "feature" will break compatibility with existing web sites, which browser vendors are very reluctant to do.
You're correct in saying that it's not a good idea. It's a profoundly bad idea and can lead to naming conflicts as well as unnecessary pollution of the global namespace.
It's an old IE feature, not recommended to use. Several browsers implement it, often as nonenumerable properties of the window object. FF, for example, does it only in quirks mode.
For further reading see duplicate Is there a spec that the id of elements should be made global variable?...
Related
In an effort to write more expressive HTML, I feel custom HTML elements are a good way for any webapp or document I may write to have good meaning gleamed from the tag name itself without the use of comments.
It appears I can define a custom HTML element with:
document.registerElement("x-el");
However it also appears that I can use a custom element before defining it:
<body>
<x-salamander>abc</x-salamander>
</body>
Or even:
<salamander>abc</salamander>
I suppose this is invalid HTML, however both Firefox and Chromium proceed to display the element without any problems or console warnings.
I can even execute the following with no complaints from the browser:
document.getElementsByTagName("salamander")[0]
Using this tag name as a selector in CSS also works fine. So, what problems might I face if I use undeclared elements in this way?
The problem with what you're trying to do is not that we can tell you it will break in some expected ways. It's that when you deviate from standards in this way, no one knows what to expect. It is, by definition, undefined, and the behavior of browsers that see it is also undefined.
That said, it might work great! Here's the things to keep in mind:
The HTMLUnknownElement interface is what you're invoking to make this work in a supported way - as far as I can tell in 5 minutes of searching, it was introduced in the HTML5 spec, so in HTML5 browsers that use it appropriately, this is no longer an undefined scenario. This is where registerElement comes into play, which can take an HTMLUnknownElement and make it known.
Browsers are typically very good at coping with unexpected markup... but it won't always result in great things (see: quirks mode).
Not all browsers are created equal. Chrome, Firefox, Safari, Opera, even IE will likely have some reliable way to handle these elements reliably (even pre-HTML5)... but I have no idea what a screen reader (Lynx) or various other esoteric, outdated, niche or even future browsers will do with it.
Everyone has said the same thing, but it's worth noting: you will fail validation. It's OK to have validation errors on your page so long as you know what they are and why they are there, and this would qualify, but you'd better have a good reason.
Browsers have a long history of taking whatever you give them and trying to do something reasonable with it, so you're likely to be OK, and if you are interested in primarily targeting HTML5 browsers, then you're very likely to be OK. As with everything HTML related, the only universal advice is to test your target demographic.
First problem I can see is that IE8 and lower will not apply your styling consistently. Even with "css resets", I get issues in IE8. It's important for the browser to know whether it's dealing with a block, inline block, list, etc, as many CSS behaviors are defined by the element type.
Second, I've never tried this, but if you use jQuery or another framework, I don't think they're built to handle non HTML tags as targets. You could create issues for your coders.
And HTML validators will probably have heart-attacks, so you lose a valuable tool.
You are re-inventing the wheel here. AngularJS has already solved the problem of adding HTML elements and attributes via what it calls directives:
Angular's HTML compiler allows the developer to teach the browser new
HTML syntax. The compiler allows you to attach behavior to any HTML
element or attribute and even create new HTML elements or attributes
with custom behavior. Angular calls these behavior extensions
directives.
The goal of Angular is broader in that it treats HTML as if HTML were a tool meant to build applications instead of just display documents. To me, this broader goal gives real meaning and purpose to the ability to extend HTML as described in your question.
You should use the namespaced version document.createElementNS instead of plain document.createElement. As you can see in the snippet below,
(...your custom element...) instanceof HTMLUnknownElement
will return false if you do that (it will be true when you do it unnamespaced)
I strongly suspect that validators won't even complain, because it's in your own namespace, and the validator (unless written by a stupid person) will (at least, really really really should) acknowledge that the 'namespaced stuff' is something it doesn't know enough about to condemn it.
New (formerly custom) elements arising in future HTML versions is a certain thing to happen, and it will happen even more often for namespaced elements compared to elements in the default namespace. And the 'HTML specs crowd' is simply not in charge of what, for example, the 'SVG spec crowd' will be doing next year or in 10. And which new namespaces will be introduced by god knows who and become common. They know they are not 'in charge of that', because they aren't stupid. For those reasons, you can bet your last shirt that you will not run into any serious problems (like errors being thrown or something of that sort) when you just go ahead and use them - it's OK if you're the first one. The worst thing that could possibly happen is that they don't look (aren't rendered) the way you'd wish, if you didn't write any CSS for them; anyway, the foremost use-case are probably invisible elements (you can be sure that display:none will work on your custom elements) and "transparent containers" (which won't effect the rest of the CSS unless you have ">" somewhere in the CSS). Philosophically, what you're doing is very much akin to jQuery using class names to better be able to transform the document in certain ways. And there is absolutely nothing wrong with jQuery doing that, and if the class in question is not referenced by some CSS, that does not make the slightest difference. In the same fashion, there is absolutely nothing wrong when you use custom elements. Just use the namespaced version. That way, you're also safe to use any names that might later be added to 'proper' HTML without causing any conflicts with how those elements later will be supposed to work.
And if - surprisingly - some validator does complain, what you should do is go on with your custom elements and ditch that validator. A validator complaining about how you use your very own namespace you just came up with is akin to a traffic cop visiting you at your home and complaining about the fashion in which you use your restroom - ditch it, got me?
bucket1 = document.getElementById('bucket1');
console1 = document.getElementById('console1');
bucket2 = document.getElementById('bucket2');
console2 = document.getElementById('console2');
chicken = document.createElement('chicken');
chicken.textContent = 'gaak';
bucket1.appendChild(chicken);
console1.appendChild(document.createTextNode([
chicken instanceof HTMLUnknownElement,
chicken.namespaceURI,
chicken.tagName
].join('\n')));
rooster = document.createElementNS('myOwnNSwhereIamKing', 'roosterConFuoco');
rooster.textContent = 'gaakarissimo multo appassionata';
bucket2.appendChild(rooster);
console2.appendChild(document.createTextNode([
rooster instanceof HTMLUnknownElement,
rooster.namespaceURI,
rooster.tagName
].join('\n')));
=====chicken=====<br>
<div id='bucket1'></div>
<pre id='console1'></pre>
=====rooster=====<br>
<div id='bucket2'></div>
<pre id='console2'></pre>
MDN article
plus, you've got almost universal browser support for createElementNS.
hmmm... just found out that if you use .createElementNS, the created elements don't have the dataset property. You can still use .setAttribute('data-foo', 'bar') but .dataset.foo='bar' would have been nicer. I almost feel like downvoting my own answer above. Anyway, I hereby frown upon the browser vendors for not putting in dataset.
If there is an element like this:
var c = document.createElement('a');
Then one can add the attribute name simply by doing:
c.name = "a1";
What is the purpose of setAttribute() if one can just use the dot notation?
An attribute is not the same thing as a property.
Attributes are usually created in your HTML, and will become an object member of element.attributes. Some will also set a corresponding property.
There are some attributes that update when you change the property, but others that do not. For example, the .value property will not change the attribute on input elements. Or custom properties do not become custom attributes.
Most of the time you probably want to set the property, but if you want to change the attribute, then in some cases you must use setAttribute
Who says you can do either?
Well, okay you can. But seriously, "who says?", because it mostly comes down to that.
In the beginning, there was Netscape Navigator 2, the first web browser to support Javascript, and indeed being a few months prior to server-side use in Netscape Enterprise Server, the first anything to support Javascript (called "Livescript" in a beta version but quickly renamed "Javascript" because it was 1995 and putting the word "java" in anything was a sure-fire way to get about 20,000 column-inches out of tech journalists who spent the rest of their time wondering confused around coffee wholesalers wondering where the press releases and promotional schwag was).
The object model at the time was pretty small, to the point that you could learn it to the point where you could hold the entire model in your head in a couple of days. For most elements, you couldn't actually do very much with them. A lot of things were quite fiddly (where you can find the current value of a <select id="selId" name="selName"> today with document.getElementById('selId').value and a few other ways, then you would need document.forms[0]["selName"].options[document.forms[0]["selName"].selectedIndex].value.
Then IE3 came out with Javascript too, NN 3 upped the ante by letting you change an image's src attribute. The browser wars had begun in earnest. Many veterans are still haunted by the memories of what they did.
The really obvious way to make a browser's document model better, was to have more and more things reflected by properties - preferably writable rather than read-only. The next-best thing was to have a slightly simpler and easier to remember way of changing something than the other browser (then they might make more web pages that worked in the latest version of your browser and didn't in your rival's).
Through keeping up a rapid pace of development, it was clear that Netscape would develop a new middleware platform that would make the position of Microsoft and Apple irrelevant, while the jury was out on whether yahoo or alta-vista had the approach to search and/or directory that would dominate the web. (Don't make long-term predictions about technology).
During the general trend of make-script-able-to-do-everything-to-everything, a lot of properties got named after the corresponding attribute when there was one, which is after all a pretty sensible way.
This is a bit inconsistent though. For one thing, most properties that correspond to attributes map string values to string values in a straight-forward way. One or two do not, such as the href attribute on anchor elements which gives you a richer object with properties reflecting parts of the URI (mostly because it was available from the early days before make-script-able-to-do-everything-to-everything). Which is both useful (if you want to break the URI down) and a nuisance because there's no good way of telling which is which.
At the height of this, they had something called DHTML, and something called dHTML, which were two ways to do pretty much the same thing in completely incompatible ways.
There's also the fact that javascript is loose in letting you add a new property to anything, and HTML lets you add in new attributes (debatable, depending on how strictly you stay to which standard, but this was the browser wars and new proprietary attributes were seemingly added by one browser or another every 4 minutes). Knowing whether a property would have any real effect on any given browser was a nuisance.
Meanwhile, in a distant International Standards Consortium, something called XML was being developed. It let you add all sorts of elements with all sorts of attributes in all sorts of ways. Ways of dealing with this in script were also added.
We needed a way to more consistently change the attributes of elements than that currently existing, and since it was obvious that all future versions of HTML would be XML applications (Don't make long-term predictions about technology) it made sense for it to be at least relatively consistent between the two.
It was also dawning on everyone, that having a more popular browser than everyone else wasn't going to turn anyone into the next Bill Gates (not even the current Bill Gates) so the advantages of having greater support for standard approaches rather than greater flashy-stuff-the-other-guy-can't-do became more apparent.
The W3C DOM became more and more finalised and more and more supported. It gave us a more consistent way of setting attributes. It was more verbose, but you could know consistently what it was going to do, and it was also more powerful in creating, copying, changing and deleting parts of a document.
But old sites had to be kept going if possible, along with the fact that it does remain a useful shorthand for a lot of attributes to just set the corresponding property, so people weren't going to stop using it. Still, the DOM approach is supported to some extent by all browsers, giving much more consistency between them.
And then half the developers started using JQuery anyway.
This is to make some custom attribute:
while its all fine to make el.name='aaa';
if you make el.customsttr='a' it will not work.
-- (unless it has been already defined, as pointed out below)
http://jsfiddle.net/sXdHB/
Application:
For example you have an img, with attr 'src', then you might want to add a custom atribute 'big_src' and then read it through some script to display a bigger one;
I'd use getAttribute/setAttribute to make it clear that you're working with DOM elements. Minimizing ambiguity is a plus!
However, this is what quirksmode.org has to say about atrributes:
Attributes
A bloody mess. Try influencing attributes in this order:
Try getting or setting a specific property, like x.id or y.onclick.
If there is no specific property, use getAttribute() or
setAttribute().
If even that doesn't work, try any other method or
property in the table below. Most have horrible browser
incompatibility patterns, though.
Avoid attributes[]. It's worse
than anything else.
I've got this example page where I'm trying to put the wmode of every youtube element inside the page to "transparent".
To do it I need to get all the "object > params" and "embed" tags in the page.
The page I link you works like charm in all the browser except for IE6 (haven't cheked the other IEs yet).
With IE6 I can't catch the "params" since document.getElementsByTagName('param') returns an empty object, but this doesn't happen with the "embed"!
It won't work with document.getElementsByTagName('object') as well
Here is the page http://dl.dropbox.com/u/4064417/provaJs.html
Any suggestion why it's not returning just the "param" tags?
Thank you in advance!
I recall some issue with <param/> tags and getElementsByTagName, but it's ages that I don't code in IE6. Instead of querying from document, trying to get the params calling getElementsByTagName from the <object /> itself and see if it helps:
var objects = document.getElementsByTagName("object");
for (var i = 0, object; object = objects[i++];) {
var params = object.getElementsByTagName("param");
alert(params.length);
}
I understand that you would like to keep your app backwards compatible, but this exercise runs counter-intuitive to the general direction of the industry and its efforts to put IE6 down to rest (even google has dropped support for IE6). Your time might be better invested if you focus on building a better web experience for pseudo-modern browsers instead of worrying about the legacy ones.
Food for thought - maybe use a browser detection script and encourage your users to upgrade so that they can experience your site in all of its modern glory :)
All that being said, ZER0's suggestion is dead-on. Find the "object" tags in the page, and then iterate through its children until you find the tag you're looking for. If you can't seem to grab the object tags with getElementsByTagName, you may very well have to iterate through the document.body.childNodes nodelist, checking for the typeof(N) or N.NodeName along the way.
If you must support browsers as old IE6, I would strongly recommend using a library such as jQuery rather than trying to access the DOM directly.
IE6 has a massive number of bugs and quirks that can break even the simplest and most innocuous of Javascript code. jQuery goes to great lengths to abstract these browser bugs and deficiencies away from the developer, allowing you to write code that works on all browsers.
For example rather than using document.getElementsByTagName('object'), you can use the jQuery code $('object'), which will give you the same end result, but will work around any bugs in whichever browser your end user is running.
jQuery does a whole lot more than just hide the browser bugs, of course, but if you're working with IE6, that alone is a good enough reason to use it.
(other libraries are of course available if you really don't like jQuery for some reason)
Can somebody please explain to me the internal implementation of HTML getElementById() method ?
Is it traversing whole DOM tree to find the specified element or is it intelligent enough to look for near-by elements first ?
Thank you
The implementation is entirely (er) implementation-dependent. Some browsers may use a hashmap or similar, or they may not (because although id is required to be unique, there are lots of poorly-authored pages out there that provide invalid markup with duplicated ids). Internet Explorer 6 and 7 don't even limit getElementById to id values, they conflate namespaces terribly, although Microsoft has clearly seen the light and both IE8 and IE9 improve that.
For browsers that are implemented open source, you can find out, of course. Here's a link to the WebKit source, and here's one to Mozilla's (that line number may vary a bit, if you don't land right on it, just search for GetElementById and GetElementByIdInternal). Both of those come from this related answer here on StackOverflow. (In fact, looking at that question, I think this one may be a duplicate, although as Matthew points out in a comment below, things are moving fast enough that it might justify an update...)
It depends on the browser, but most probably use a hash map from id->element. It's true that there are many invalid pages that have duplicate ids. However, the browser will still only return one element, not a collection.
I don't know what you mean by "near by elements" since the method only exists on document.
If you're interested, you can find the implementation for free software browsers such as Firefox and Chrome.
That depends. The method is implemented by each web browser vendor, so the details may be different from one to another and possibly from one version of a browser to another.
I'd suggest taking a look at the source code for a browser such as Mozilla Firefox and see if you can find the implementation.
Is there any particular reason that it isn't in any of the the specs?
It seems to be supported in all browsers, (although I'll admit it doesn't work right in all of them...since you have to use libraries like innerXHTML to get it to work right thanks to Internet Explorer.
Is innerHTML in danger of disappearing from forthcoming versions of browsers? If not shouldn't they just add it already?
I'm marking this community wiki as I know I'm gonna take a beating on my rep for this...but I just wondered why...
http://dev.w3.org/html5/spec/Overview.html#innerhtml
There's absolutely no way it's in danger, thousands of applications rely on it and doing so would be a horrible idea.
I'll admit it doesn't work right in all of them...since you have to use libraries like innerXHTML to get it to work right thanks to Internet Explorer.
IE invented innerHTML; you can't really expect it to work any better than it does there.
Is there any particular reason that it isn't in any of the the specs?
It's proposed for HTML5, for what it's worth. There is certainly no danger of it disappearing in the future, though you should continue to use it only for the simple cases where you are writing straight ‘block’ or ‘inline’ element content. Special cases like tables and selects are going to continue to be troublesome.
IE, being the inventor of dynamically modifying the content has gone with it all the way - other browsers didn't!
Passing the string as innerHTML means that the string will get through a normalization process before it gets passed to the element. Meaning it will get transformed fom a string into a proper html parsing content.
Firefox implemented it wrongly. It doesn't distinguish between html:innerHTML and html:innerText and plain string:text. The difference is literally obvious for IE, but not for FF. Hence the difference in handling situations and the confusion of FF only coders when they go back to the master.