Getting an element’s html, not just the innerHTML
jQuery January 13th, 2009The original content of this post involved a little function I wrote called “getNodeHtml”, which basically wrapped a given HTML element with a parent node, got the innerHTML of that temporary parent node, reset the DOM to its previous state, then returned the HTML string. I also used jQuery in the function, which seemed unnecessary to me.
Today I saw that IE has an outerHTML property, which does exactly what I need. I generally avoid giving IE credit, but they get a chocolaty kudos bar for this one.
The Array.indexOf() function I have gave me the idea to extend the prototype of the HTMLElement object so I could have it at my fingertips, and use the same property call in FF and IE (amoung others). After spending some time trying to add a “get outerHTML” property to the HTMLElement object, I found some useful info on Javascript Getters and Setters that pointed me in the right direction. The result…
if(document.__defineGetter__ && !HTMLElement.outerHTML){
HTMLElement.prototype.__defineGetter__(”outerHTML”, function(){
var parent = this.parentNode;
var span = document.createElement(”span”);
span.appendChild(this);
var HTML = span.innerHTML;
parent.appendChild(this);
delete span;
return HTML;
});
}
The __define[SG]etter__ methods do not exist in IE, so I’m still curious how to add a getter/setter to an existing prototype there. We could just create functions like value(’test’, ’set’) / value(null, ‘get’) or setValue(’test’) / getValue(), but bleh…those are methods, not properties.
********************UPDATE************************
I have found that manipulating the DOM momentarily to get the outerHTML of an element can cause some problems when you’re doing alot of DOM manipulation simultaneously. Instead, the following method builds the HTML of the current element by looping through its attributes - much more reliable!
if (document.__defineGetter__ && !HTMLElement.outerHTML) {
HTMLElement.prototype.__defineGetter__("outerHTML", function(){
var emptyTags = {
"img": true,
"br": true,
"input": true,
"meta": true,
"link": true,
"param": true,
"hr": true
};
var attrs = this.attributes,
tagName = this.tagName.toLowerCase(),
str = "<" + tagName;
for (var a = 0; a < attrs.length; a++)
str += " " + attrs[a].name + "=\"" + attrs[a].value + "\"";
if (emptyTags[tagName])
return str + "/>";
return str + ">" + this.innerHTML + "" + tagName + ">";
});
}
October 14th, 2008 at 4:31 pm
[...] that you can use my getNodeHtml function so that you aren’t stuck with moving the innerHTML of the elements around. View the source of [...]
November 5th, 2008 at 11:50 am
Thanks for posting this function. I can’t help thinking that there must be a cleaner way to get the full html out of jquery, but this will work for now.
(By the way, the display of the code in your post breaks at your wrapped “div id=”tmpGetNodeHtml”. I had to look at source to get it.)
November 26th, 2008 at 8:38 pm
I thought so too…guess not :/. Glad this helps!
I do need to get a better solution for posting code samples here. Seems like the Wordpress html editor tears up the formatting when I go from wysiwyg to html mode.
July 1st, 2009 at 6:08 pm
Hey Stephen, Thanks for making this post. I had the same problems with jQuery. However, I was able to find a way to do it with Dojo…so far I’ve found a combination of the two libraries, Dojo and jQuery is necessary to handle most functionality. Neither does it alone. At least not yet.
myElement=dojo.query(’#someId’)[0].parentNode.innerHTML;
November 3rd, 2009 at 12:11 pm
Aaron, I’d be glad to give you some jQuery tips where you think you might need to use Dojo. The truth is, jQuery is pretty much all you need. Libraries like Dojo and jQuery are mostly useful for DOM traversal, animations, and cross-browser compatibility. Everything else can be handled with custom scripts. The libraries just eliminate most of the guess-work.
What you’re doing above with Dojo is really just selecting the parent node of your element. You don’t need jQuery or Dojo to do that. With native javascript, you’d just do document.getElementById(”someId”).parentNode.innerHTML. The only problem with that is that if your node has siblings (that is, other nodes with the same heirarchy), it will grab the HTML for all of those too. That’s not what you want.
Check out the update in the post above. The original method manipulated the DOM, which proved problematic is some select cases where other heavy DOM manipulation is going on. The new method builds the html of the current tag dynamically.