What are the drawbacks of accessing DOM elements directly by ID? - javascript

Today I stumbled upon the possibility to access a DOM element in Javascript simply by its id e.g. like this:
elementid.style.backgroundColor = "blue"
I tested with a very short snippet if this works in IE, Firefox and Chrome - and it does.
Here is the snippet I used:
<html><head>
<script>
function highlight() {
content.style.backgroundColor = "blue";
content.style.color = "white";
}
</script>
</head>
<body>
<div id="content">test content</div>
<div onclick="highlight()">highlight content</div>
</body></html>
So I wondered in which cases document.getElementById('elementid') should be used (or similar framework replacements like $()) and what are the drawbacks of the direct access.
I was not able to find any useful documentation on this. Everywhere either getElementById or framework methods are used.

It is propriety Microsoft gubbins. It doesn't work in lots of browsers — especially in standards mode (and you want standards mode to avoid quirks mode inconsistencies such as IE getting width wrong).

You should also be concerned about name space. Right now you're treating it as if it's a variable in the global name space, and you would have to trust neither you nor any libraries that you include declare any global variables with the same name as DOM id's. The same goes for your highlight function.
Also while id's with dashes are perfectly valid, those would be inaccessible via this method.
e.g. <div id="container-wrapper"><div id="container"> ... </div></div>
would become container-wrapper.style.color which would then try to subtract wrapper.style.color from container.

It’s not a part of any standard. Besides, simple variables can be overwriten. Var content could be redeclared in any place of your script, or external library (and, yes, I know global variables are evil, but ppl still use them…) and your script will break.
And, naturally, you cannot use IDs like alert or document etc.

Related

Document.write nondestructive alternative [duplicate]

In tutorials I've learnt to use document.write. Now I understand that by many this is frowned upon. I've tried print(), but then it literally sends it to the printer.
So what are alternatives I should use, and why shouldn't I use document.write? Both w3schools and MDN use document.write.
The reason that your HTML is replaced is because of an evil JavaScript function: document.write().
It is most definitely "bad form." It only works with webpages if you use it on the page load; and if you use it during runtime, it will replace your entire document with the input. And if you're applying it as strict XHTML structure it's not even valid code.
the problem:
document.write writes to the document stream. Calling document.write on a closed (or loaded) document automatically calls document.open which will clear the document.
-- quote from the MDN
document.write() has two henchmen, document.open(), and document.close(). When the HTML document is loading, the document is "open". When the document has finished loading, the document has "closed". Using document.write() at this point will erase your entire (closed) HTML document and replace it with a new (open) document. This means your webpage has erased itself and started writing a new page - from scratch.
I believe document.write() causes the browser to have a performance decrease as well (correct me if I am wrong).
an example:
This example writes output to the HTML document after the page has loaded. Watch document.write()'s evil powers clear the entire document when you press the "exterminate" button:
I am an ordinary HTML page. I am innocent, and purely for informational purposes. Please do not <input type="button" onclick="document.write('This HTML page has been succesfully exterminated.')" value="exterminate"/>
me!
the alternatives:
.innerHTML This is a wonderful alternative, but this attribute has to be attached to the element where you want to put the text.
Example: document.getElementById('output1').innerHTML = 'Some text!';
.createTextNode() is the alternative recommended by the W3C.
Example: var para = document.createElement('p');
para.appendChild(document.createTextNode('Hello, '));
NOTE: This is known to have some performance decreases (slower than .innerHTML). I recommend using .innerHTML instead.
the example with the .innerHTML alternative:
I am an ordinary HTML page.
I am innocent, and purely for informational purposes.
Please do not
<input type="button" onclick="document.getElementById('output1').innerHTML = 'There was an error exterminating this page. Please replace <code>.innerHTML</code> with <code>document.write()</code> to complete extermination.';" value="exterminate"/>
me!
<p id="output1"></p>
Here is code that should replace document.write in-place:
document.write=function(s){
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
lastScript.insertAdjacentHTML("beforebegin", s);
}
You can combine insertAdjacentHTML method and document.currentScript property.
The insertAdjacentHTML() method of the Element interface parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position:
'beforebegin': Before the element itself.
'afterbegin': Just inside the element, before its first child.
'beforeend': Just inside the element, after its last child.
'afterend': After the element itself.
The document.currentScript property returns the <script> element whose script is currently being processed. Best position will be beforebegin — new HTML will be inserted before <script> itself. To match document.write's native behavior, one would position the text afterend, but then the nodes from consecutive calls to the function aren't placed in the same order as you called them (like document.write does), but in reverse. The order in which your HTML appears is probably more important than where they're place relative to the <script> tag, hence the use of beforebegin.
document.currentScript.insertAdjacentHTML(
'beforebegin',
'This is a document.write alternative'
)
As a recommended alternative to document.write you could use DOM manipulation to directly query and add node elements to the DOM.
Just dropping a note here to say that, although using document.write is highly frowned upon due to performance concerns (synchronous DOM injection and evaluation), there is also no actual 1:1 alternative if you are using document.write to inject script tags on demand.
There are a lot of great ways to avoid having to do this (e.g. script loaders like RequireJS that manage your dependency chains) but they are more invasive and so are best used throughout the site/application.
I fail to see the problem with document.write. If you are using it before the onload event fires, as you presumably are, to build elements from structured data for instance, it is the appropriate tool to use. There is no performance advantage to using insertAdjacentHTML or explicitly adding nodes to the DOM after it has been built. I just tested it three different ways with an old script I once used to schedule incoming modem calls for a 24/7 service on a bank of 4 modems.
By the time it is finished this script creates over 3000 DOM nodes, mostly table cells. On a 7 year old PC running Firefox on Vista, this little exercise takes less than 2 seconds using document.write from a local 12kb source file and three 1px GIFs which are re-used about 2000 times. The page just pops into existence fully formed, ready to handle events.
Using insertAdjacentHTML is not a direct substitute as the browser closes tags which the script requires remain open, and takes twice as long to ultimately create a mangled page. Writing all the pieces to a string and then passing it to insertAdjacentHTML takes even longer, but at least you get the page as designed. Other options (like manually re-building the DOM one node at a time) are so ridiculous that I'm not even going there.
Sometimes document.write is the thing to use. The fact that it is one of the oldest methods in JavaScript is not a point against it, but a point in its favor - it is highly optimized code which does exactly what it was intended to do and has been doing since its inception.
It's nice to know that there are alternative post-load methods available, but it must be understood that these are intended for a different purpose entirely; namely modifying the DOM after it has been created and memory allocated to it. It is inherently more resource-intensive to use these methods if your script is intended to write the HTML from which the browser creates the DOM in the first place.
Just write it and let the browser and interpreter do the work. That's what they are there for.
PS: I just tested using an onload param in the body tag and even at this point the document is still open and document.write() functions as intended. Also, there is no perceivable performance difference between the various methods in the latest version of Firefox. Of course there is a ton of caching probably going on somewhere in the hardware/software stack, but that's the point really - let the machine do the work. It may make a difference on a cheap smartphone though. Cheers!
The question depends on what you are actually trying to do.
Usually, instead of doing document.write you can use someElement.innerHTML or better, document.createElement with an someElement.appendChild.
You can also consider using a library like jQuery and using the modification functions in there: http://api.jquery.com/category/manipulation/
This is probably the most correct, direct replacement: insertAdjacentHTML.
Try to use getElementById() or getElementsByName() to access a specific element and then to use innerHTML property:
<html>
<body>
<div id="myDiv1"></div>
<div id="myDiv2"></div>
</body>
<script type="text/javascript">
var myDiv1 = document.getElementById("myDiv1");
var myDiv2 = document.getElementById("myDiv2");
myDiv1.innerHTML = "<b>Content of 1st DIV</b>";
myDiv2.innerHTML = "<i>Content of second DIV element</i>";
</script>
</html>
Use
var documentwrite =(value, method="", display="")=>{
switch(display) {
case "block":
var x = document.createElement("p");
break;
case "inline":
var x = document.createElement("span");
break;
default:
var x = document.createElement("p");
}
var t = document.createTextNode(value);
x.appendChild(t);
if(method==""){
document.body.appendChild(x);
}
else{
document.querySelector(method).appendChild(x);
}
}
and call the function based on your requirement as below
documentwrite("My sample text"); //print value inside body
documentwrite("My sample text inside id", "#demoid", "block"); // print value inside id and display block
documentwrite("My sample text inside class", ".democlass","inline"); // print value inside class and and display inline
I'm not sure if this will work exactly, but I thought of
var docwrite = function(doc) {
document.write(doc);
};
This solved the problem with the error messages for me.

Do custom markup tags placed in an HTML document affect the flow and is it possible to parse them with JS? [duplicate]

This question already has answers here:
Is there a way to create your own html tag in HTML5?
(18 answers)
Closed 8 years ago.
Would it be possible to do the following
<body>
<main>
<!-- CONTENT -->
</main>
<foot>
<!-- FOOTER CONTENT -->
</foot>
</body>
if I then wrote some JavaScript that did something along the lines of the following. Please note that I don't want you to write the actual code that goes here. This is just a mockup of the core functionality.
for(elem inside main){
elem.makeItBig();
}
for(elem inside foot){
if(elem is img){
elem.makeItSmall();
}
}
I am aware of this post Is there a way to create your own html tag in HTML5?. But I don't really want to create tags to style them but rather to provide identifying attributes to the DOM which I can hook into using JavaScript. Imagine something kind of like a class, but used in a way that you can stitch lots of PHP generated parts together using these tags.
If you use a made up tag in HTML is it ignored by your browser or will it throw an error.
You can use your own tags as far as I'm aware.
You'd need to do some mucking about to get them to work in older IE browsers.
The more important point is - why on earth would you want to? It wouldn't make your code very maintainable or future-proof. Just use classes on proper elements.
Can you create custom tags? yes. Is it a good idea? not really because your tag may not be recognized by some browsers as a valid html standard. you can check this: http://www.w3.org/MarkUp/html-spec/html-spec_4.html#SEC4.2.1
For custom elements specifications you can look at standards specification for custom elements : http://w3c.github.io/webcomponents/spec/custom/
Although your approach seems nice, just think about changing the size of another group of elements ... you would probably use the same function so why not do this:
var makeItBig = function(elem){...};
for(elem in main){
makeItBig(main[elem]);
}
this way you won't have to create a new method for each element you need to change.
But if you really need it that way you can make it like this:
var makeItBigFunction = function(){var elem = this; ...};
// create new methods
for(elem in main){
main[elem].makeItBig = makeItBigFunction;
}
// make use of them
for(elem in main){
main[elem].makeItBig();
}
Notice that there is a big difference between DOM object's properties (or methods) and HTML attributes.
Read more about it: Properties and Attributes in HTML
Feel free to use HTML5 tags like <content>, <header>, <footer>, <aside> etc.
You can read more about them here: http://www.w3schools.com/html/html5_new_elements.asp in section "New Semantic/Structural Elements". Those should be considered as supported in most modern browsers. Actually, you may use any other custom tags, however their default properties (display, position etc.) may be unpredictable.

Javascript library to gracefully downgrade custom elements in HTML at runtime

I would like to say
<html>
<body>
<mytag foo="bar">blah</mytag>
</body>
</html>
And define somewhere else how a <mytag> should behave. But for older browsers that do not play nicely with custom tags, I would like to just load a js library in the browser and have it automatically rewrite the above code as say
<html>
<body>
<div data-mytag data-foo="bar">blah</div>
</body>
</html>
Obviously this functionality could be hacked together in an hour, but I would prefer to use a tiny library that someone has written, for the sake of convention and possibly handy features. Do you know of one? Note: please don't reply about why I shouldn't use custom tags.
For the first part, maybe something like
<mytag>yo</mytag>
<script>
var map = {
MYTAG: function(s){
// surround content with stars
return '**'+s+'**';
}
}
Array.prototype.slice.call(document.getElementsByTagName('*')).forEach(function(tag){
// note on some IE versions you cant set innerHTML directly
if(map[tag.tagName]) tag.innerHTML = map[tag.tagName](tag.innerHTML);
})
</script>
For changing element tags at runtime, I can't recall if that's possible. People may cringe, but I'd maybe take the entire document.body.innerHTML replace it using regexes and reset it. If I knew I was the only creator of the HTML content that may take care of it..

Will it work in every browser even though <div /> is not a valid HTML element?

Is $("<div />").appendTo($mySelector) safe to use? Will it work in every browser even though is not a valid HTML element?
I'm asking because it's really easier to use than $("<div><div />")
Yes. If you look at the source this case is even optimized.
/^<(\w+)\s*\/?>(?:<\/\1>|)$/
<div / > // your case
This regexp will match if there is or is not a /, and it is not included in a group. The only grouped expression is the actual tag name (div), which is used.
If you look more closesly you can see that the following are all handled the very same way:
<div>
<div />
<div></div>
<div /></div>
It will work correctly. jQuery handles the translation.
Yes, but why not use $(document.createElement('div')); it is faster than using the jquery to create the element. It will work without running a regex and requiring translation by jquery.
See this SO answer for a test of using different methods for element creation

What are alternatives to document.write?

In tutorials I've learnt to use document.write. Now I understand that by many this is frowned upon. I've tried print(), but then it literally sends it to the printer.
So what are alternatives I should use, and why shouldn't I use document.write? Both w3schools and MDN use document.write.
The reason that your HTML is replaced is because of an evil JavaScript function: document.write().
It is most definitely "bad form." It only works with webpages if you use it on the page load; and if you use it during runtime, it will replace your entire document with the input. And if you're applying it as strict XHTML structure it's not even valid code.
the problem:
document.write writes to the document stream. Calling document.write on a closed (or loaded) document automatically calls document.open which will clear the document.
-- quote from the MDN
document.write() has two henchmen, document.open(), and document.close(). When the HTML document is loading, the document is "open". When the document has finished loading, the document has "closed". Using document.write() at this point will erase your entire (closed) HTML document and replace it with a new (open) document. This means your webpage has erased itself and started writing a new page - from scratch.
I believe document.write() causes the browser to have a performance decrease as well (correct me if I am wrong).
an example:
This example writes output to the HTML document after the page has loaded. Watch document.write()'s evil powers clear the entire document when you press the "exterminate" button:
I am an ordinary HTML page. I am innocent, and purely for informational purposes. Please do not <input type="button" onclick="document.write('This HTML page has been succesfully exterminated.')" value="exterminate"/>
me!
the alternatives:
.innerHTML This is a wonderful alternative, but this attribute has to be attached to the element where you want to put the text.
Example: document.getElementById('output1').innerHTML = 'Some text!';
.createTextNode() is the alternative recommended by the W3C.
Example: var para = document.createElement('p');
para.appendChild(document.createTextNode('Hello, '));
NOTE: This is known to have some performance decreases (slower than .innerHTML). I recommend using .innerHTML instead.
the example with the .innerHTML alternative:
I am an ordinary HTML page.
I am innocent, and purely for informational purposes.
Please do not
<input type="button" onclick="document.getElementById('output1').innerHTML = 'There was an error exterminating this page. Please replace <code>.innerHTML</code> with <code>document.write()</code> to complete extermination.';" value="exterminate"/>
me!
<p id="output1"></p>
Here is code that should replace document.write in-place:
document.write=function(s){
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
lastScript.insertAdjacentHTML("beforebegin", s);
}
You can combine insertAdjacentHTML method and document.currentScript property.
The insertAdjacentHTML() method of the Element interface parses the specified text as HTML or XML and inserts the resulting nodes into the DOM tree at a specified position:
'beforebegin': Before the element itself.
'afterbegin': Just inside the element, before its first child.
'beforeend': Just inside the element, after its last child.
'afterend': After the element itself.
The document.currentScript property returns the <script> element whose script is currently being processed. Best position will be beforebegin — new HTML will be inserted before <script> itself. To match document.write's native behavior, one would position the text afterend, but then the nodes from consecutive calls to the function aren't placed in the same order as you called them (like document.write does), but in reverse. The order in which your HTML appears is probably more important than where they're place relative to the <script> tag, hence the use of beforebegin.
document.currentScript.insertAdjacentHTML(
'beforebegin',
'This is a document.write alternative'
)
As a recommended alternative to document.write you could use DOM manipulation to directly query and add node elements to the DOM.
Just dropping a note here to say that, although using document.write is highly frowned upon due to performance concerns (synchronous DOM injection and evaluation), there is also no actual 1:1 alternative if you are using document.write to inject script tags on demand.
There are a lot of great ways to avoid having to do this (e.g. script loaders like RequireJS that manage your dependency chains) but they are more invasive and so are best used throughout the site/application.
I fail to see the problem with document.write. If you are using it before the onload event fires, as you presumably are, to build elements from structured data for instance, it is the appropriate tool to use. There is no performance advantage to using insertAdjacentHTML or explicitly adding nodes to the DOM after it has been built. I just tested it three different ways with an old script I once used to schedule incoming modem calls for a 24/7 service on a bank of 4 modems.
By the time it is finished this script creates over 3000 DOM nodes, mostly table cells. On a 7 year old PC running Firefox on Vista, this little exercise takes less than 2 seconds using document.write from a local 12kb source file and three 1px GIFs which are re-used about 2000 times. The page just pops into existence fully formed, ready to handle events.
Using insertAdjacentHTML is not a direct substitute as the browser closes tags which the script requires remain open, and takes twice as long to ultimately create a mangled page. Writing all the pieces to a string and then passing it to insertAdjacentHTML takes even longer, but at least you get the page as designed. Other options (like manually re-building the DOM one node at a time) are so ridiculous that I'm not even going there.
Sometimes document.write is the thing to use. The fact that it is one of the oldest methods in JavaScript is not a point against it, but a point in its favor - it is highly optimized code which does exactly what it was intended to do and has been doing since its inception.
It's nice to know that there are alternative post-load methods available, but it must be understood that these are intended for a different purpose entirely; namely modifying the DOM after it has been created and memory allocated to it. It is inherently more resource-intensive to use these methods if your script is intended to write the HTML from which the browser creates the DOM in the first place.
Just write it and let the browser and interpreter do the work. That's what they are there for.
PS: I just tested using an onload param in the body tag and even at this point the document is still open and document.write() functions as intended. Also, there is no perceivable performance difference between the various methods in the latest version of Firefox. Of course there is a ton of caching probably going on somewhere in the hardware/software stack, but that's the point really - let the machine do the work. It may make a difference on a cheap smartphone though. Cheers!
The question depends on what you are actually trying to do.
Usually, instead of doing document.write you can use someElement.innerHTML or better, document.createElement with an someElement.appendChild.
You can also consider using a library like jQuery and using the modification functions in there: http://api.jquery.com/category/manipulation/
This is probably the most correct, direct replacement: insertAdjacentHTML.
Try to use getElementById() or getElementsByName() to access a specific element and then to use innerHTML property:
<html>
<body>
<div id="myDiv1"></div>
<div id="myDiv2"></div>
</body>
<script type="text/javascript">
var myDiv1 = document.getElementById("myDiv1");
var myDiv2 = document.getElementById("myDiv2");
myDiv1.innerHTML = "<b>Content of 1st DIV</b>";
myDiv2.innerHTML = "<i>Content of second DIV element</i>";
</script>
</html>
Use
var documentwrite =(value, method="", display="")=>{
switch(display) {
case "block":
var x = document.createElement("p");
break;
case "inline":
var x = document.createElement("span");
break;
default:
var x = document.createElement("p");
}
var t = document.createTextNode(value);
x.appendChild(t);
if(method==""){
document.body.appendChild(x);
}
else{
document.querySelector(method).appendChild(x);
}
}
and call the function based on your requirement as below
documentwrite("My sample text"); //print value inside body
documentwrite("My sample text inside id", "#demoid", "block"); // print value inside id and display block
documentwrite("My sample text inside class", ".democlass","inline"); // print value inside class and and display inline
I'm not sure if this will work exactly, but I thought of
var docwrite = function(doc) {
document.write(doc);
};
This solved the problem with the error messages for me.

Categories