D
David Mark
How to Get and Set HTML
Setting the inner HTML of an element is often useful. When making
complicated changes to the document tree, allowing the parser to do
most of the work is often the most efficient solution. The question
of whether to deal with a string or object representation of a DOM
structure comes up often in applications that update portions of a
document with XHR results.
Despite there being no standard behind the innerHTML property and the
somewhat awkward feel of dealing with serialized DOM structures, I
virtually always choose the string over the (XML) document object.
It's much simpler, faster, requires less code, less function calls
and, having debuted in IE 4, has enough successful history behind it
to be trusted.
You've probably heard there are bugs galore with this property, but
most implementation differences can hardly be considered bugs. This
is another Microsoft invention that has been copied by every other
browser vendor. Microsoft explicitly disallowed modifying table
structures with this property. For example, you can replace entire
TABLE elements, but you can't replace a row, column group, etc. There
are existing (and standard) objects to modify table structures:-
http://msdn.microsoft.com/en-us/library/ms537484(v=vs.85).aspx
Follow the link at the bottom to the DOM 1 recommendation to find all
of the information you need to modify table structures without
stooping to setting inner HTML.
Same goes for SELECT elements, which also have specialized objects to
modify their structure (e.g. add and remove options). As with most
form controls, they are very easy to manipulate with standard code
that works in virtually every script-enabled browser ever made (even
NN 4!) See the same DOM recommendation.
Keeping these facts in mind during design can save a world of time.
I've found that most designs can do just fine sticking to the
innerHTML properties of DIV elements (and perhaps the occasional TD or
TR, which won't change the structure of containing tables).
The simplest rendition of the setter with simplified feature
detection*:-
// NOTE: Don't use this rendition with anything but DIV's
// Degrades in IE 3
if (document.documentElement && 'string' == typeof
document.documentElement.innerHTML) {
var setHTML = function(el, html) {
el.innerHTML = html;
};
}
Trying to move a complicated project with lots of developers over to
this way of setting HTML? During development, you may want to add
something like:-
if (el.tagName.toLowerCase() != 'div') {
throw new Error('Please only set inner HTML of DIV elements!');
}
....at the outset (and remove on deployment of course). All of the
trouble-making code will become apparent. Eventually, even the
developers who don't read documentation will get the message about not
modifying anything other than DIV's with the setHTML function.
Why would you even bother to wrap that functionality? For one,
because you need the feature detection. Never mind that virtually
every browser made to date has this property. Your applications
should degrade gracefully in those (past or future) browsers that are
the exceptions. Why even try to memorize which host objects and
properties are omnipresent at the moment the function is written?
Just include appropriate feature detection/testing in all function
renditions.
if (setHTML) {
// Put HTML setting application here
}
Also, however unlikely in this case, you might want to replace setHTML
with a more complicated rendition in some future application. You
might consider the debug version with the argument validation to be an
alternate rendition. I prefer to think of it as a debug version of
the same rendition.
But a better question is why you would want to try to modify table
structures by setting inner HTML. Sure, it can be be done in a
roundabout way. Ultimately it comes down to doing what you were
trying to avoid in the first place (i.e. manually appending nodes one
at a time). My Library (and the rest) all go through a lot of
rigamorale to try to make such operations "work" (as best they can)
with varied results. This is what GP libraries do. They don't help
developers avoid costly mistakes. They hide the costly mistakes
behind a "concise" API. If you could only see the mess that goes on
behind the scenes of these things, you'd be in a much better position
to make sound design decisions. Furthermore, you wouldn't be left
with code that can only be reasonably expected to "work" in five or
six of the latest versions of the "core" browsers in their default
configurations *today*.
Every time I hear "don't reinvent the wheel", I think of how many old
versions of jQuery, Dojo, Prototype, Mootools, etc. there are broken
down and rusting on the side of the highway. Also have to wonder what
the average Web developer wants with the "perfect" innerHTML wrapper.
Sure lots of library authors (typically excited and ambitious
beginners) are keen to provide such a thing (as best they can). But
who in their right mind would be in the market for it, particularly
when it is likely a clunky multi-browser facade as opposed to a clean
cross-browser solution? Which strategy do you think will save time in
the long run? Which strategy will the monolithic libraries/framework
always eschew for not having enough mass appeal?
See the problem with such libraries? They constantly strive to
overreach both practicality and the collective ability of their
authors because they are all in some sort of ridiculous competition to
be the most popular library. Does being the most popular lead to
better solutions? Of course not; jQuery is a prime example of a
script getting (much) worse as it grows more popular. It's not hard
to understand why: too many cooks with too many contexts, too many
suggestions, etc. You end up with one fuzzily-defined context (e.g.
works for me here, dude!) for hundreds of functions. Changing any one
function can alter the context in which the collection is expected to
work; it's impossible to pin such things down and no wonder that most
libraries provide little more than a set of shiny browser icons to
indicate their "supported" environments.
In contrast to setting, serializing (getting) HTML from DOM structures
is mostly useless and trying to normalize markup on the client side is
generally a waste of time. An example of an application that does
need to serialize HTML is an editor. But generally, HTML editors
don't *need* to normalize the resulting markup. That's a task for a
server side process. It's the same case as with form validation,
except that providing a client side first defense is a much more
complicated proposition. You have to write the server side validation
anyway.
* Use isHostObjectProperty to detect documentElement
http://www.cinsoft.net/
http://www.twitter.com/cinsoft
http://jsperf.com/browse/david-mark
Setting the inner HTML of an element is often useful. When making
complicated changes to the document tree, allowing the parser to do
most of the work is often the most efficient solution. The question
of whether to deal with a string or object representation of a DOM
structure comes up often in applications that update portions of a
document with XHR results.
Despite there being no standard behind the innerHTML property and the
somewhat awkward feel of dealing with serialized DOM structures, I
virtually always choose the string over the (XML) document object.
It's much simpler, faster, requires less code, less function calls
and, having debuted in IE 4, has enough successful history behind it
to be trusted.
You've probably heard there are bugs galore with this property, but
most implementation differences can hardly be considered bugs. This
is another Microsoft invention that has been copied by every other
browser vendor. Microsoft explicitly disallowed modifying table
structures with this property. For example, you can replace entire
TABLE elements, but you can't replace a row, column group, etc. There
are existing (and standard) objects to modify table structures:-
http://msdn.microsoft.com/en-us/library/ms537484(v=vs.85).aspx
Follow the link at the bottom to the DOM 1 recommendation to find all
of the information you need to modify table structures without
stooping to setting inner HTML.
Same goes for SELECT elements, which also have specialized objects to
modify their structure (e.g. add and remove options). As with most
form controls, they are very easy to manipulate with standard code
that works in virtually every script-enabled browser ever made (even
NN 4!) See the same DOM recommendation.
Keeping these facts in mind during design can save a world of time.
I've found that most designs can do just fine sticking to the
innerHTML properties of DIV elements (and perhaps the occasional TD or
TR, which won't change the structure of containing tables).
The simplest rendition of the setter with simplified feature
detection*:-
// NOTE: Don't use this rendition with anything but DIV's
// Degrades in IE 3
if (document.documentElement && 'string' == typeof
document.documentElement.innerHTML) {
var setHTML = function(el, html) {
el.innerHTML = html;
};
}
Trying to move a complicated project with lots of developers over to
this way of setting HTML? During development, you may want to add
something like:-
if (el.tagName.toLowerCase() != 'div') {
throw new Error('Please only set inner HTML of DIV elements!');
}
....at the outset (and remove on deployment of course). All of the
trouble-making code will become apparent. Eventually, even the
developers who don't read documentation will get the message about not
modifying anything other than DIV's with the setHTML function.
Why would you even bother to wrap that functionality? For one,
because you need the feature detection. Never mind that virtually
every browser made to date has this property. Your applications
should degrade gracefully in those (past or future) browsers that are
the exceptions. Why even try to memorize which host objects and
properties are omnipresent at the moment the function is written?
Just include appropriate feature detection/testing in all function
renditions.
if (setHTML) {
// Put HTML setting application here
}
Also, however unlikely in this case, you might want to replace setHTML
with a more complicated rendition in some future application. You
might consider the debug version with the argument validation to be an
alternate rendition. I prefer to think of it as a debug version of
the same rendition.
But a better question is why you would want to try to modify table
structures by setting inner HTML. Sure, it can be be done in a
roundabout way. Ultimately it comes down to doing what you were
trying to avoid in the first place (i.e. manually appending nodes one
at a time). My Library (and the rest) all go through a lot of
rigamorale to try to make such operations "work" (as best they can)
with varied results. This is what GP libraries do. They don't help
developers avoid costly mistakes. They hide the costly mistakes
behind a "concise" API. If you could only see the mess that goes on
behind the scenes of these things, you'd be in a much better position
to make sound design decisions. Furthermore, you wouldn't be left
with code that can only be reasonably expected to "work" in five or
six of the latest versions of the "core" browsers in their default
configurations *today*.
Every time I hear "don't reinvent the wheel", I think of how many old
versions of jQuery, Dojo, Prototype, Mootools, etc. there are broken
down and rusting on the side of the highway. Also have to wonder what
the average Web developer wants with the "perfect" innerHTML wrapper.
Sure lots of library authors (typically excited and ambitious
beginners) are keen to provide such a thing (as best they can). But
who in their right mind would be in the market for it, particularly
when it is likely a clunky multi-browser facade as opposed to a clean
cross-browser solution? Which strategy do you think will save time in
the long run? Which strategy will the monolithic libraries/framework
always eschew for not having enough mass appeal?
See the problem with such libraries? They constantly strive to
overreach both practicality and the collective ability of their
authors because they are all in some sort of ridiculous competition to
be the most popular library. Does being the most popular lead to
better solutions? Of course not; jQuery is a prime example of a
script getting (much) worse as it grows more popular. It's not hard
to understand why: too many cooks with too many contexts, too many
suggestions, etc. You end up with one fuzzily-defined context (e.g.
works for me here, dude!) for hundreds of functions. Changing any one
function can alter the context in which the collection is expected to
work; it's impossible to pin such things down and no wonder that most
libraries provide little more than a set of shiny browser icons to
indicate their "supported" environments.
In contrast to setting, serializing (getting) HTML from DOM structures
is mostly useless and trying to normalize markup on the client side is
generally a waste of time. An example of an application that does
need to serialize HTML is an editor. But generally, HTML editors
don't *need* to normalize the resulting markup. That's a task for a
server side process. It's the same case as with form validation,
except that providing a client side first defense is a much more
complicated proposition. You have to write the server side validation
anyway.
* Use isHostObjectProperty to detect documentElement
http://www.cinsoft.net/
http://www.twitter.com/cinsoft
http://jsperf.com/browse/david-mark