Document CreateTag Method
As I worked on the GameEngine improvements, I realized that it would be nice to have a menu and several other DOM elements. Since the engine will be standalone, it is necessary to dynamically create the DOM elements required to run the game. For this task, I have use a method “document.createTag()”, which I often refactor for various projects. In its most basic form, it looks like the following:
Example 1: document.createTag
YAHOO.lang.augmentObject(document, { /** * Creates and returns an html element and adds attributes from the hash. * * @method createTag * @param tagName {String} Required. Tag name to create. * @param h {Object} Optional. The hashtable of attributes, styles, and classes; defaults is empty object. * @return {Element} The newly created element; returns null otherwise. * @static */ createTag: function(tagName, h) { var Dom = YAHOO.util.Dom, node = document.createElement(tagName), hash = isType(h, ‘object’) ? h : {}; // iterate through the possible attributes for (var k in hash) { var v = hash[k]; k = k.toLowerCase(); if (isType(v, ’string’) || (’style’ === k && isType(v, ‘object’))) { switch (k) { case ‘classname’: case ‘klass’: case ‘class’: case ‘cls’: Dom.addClass(node, v); break; case ‘cellpadding’: node.cellPadding = v; break; case ‘cellspacing’: node.cellSpacing = v; break; case ‘colspan’: node.colSpan = v; break; case ‘checked’: case ‘disabled’: node[k] = v; break; case ‘rowspan’: node.rowSpan = v; break; case ’style’: // iterate through the style object for (var t in v) { var s = v[t]; if (isType(s, ’string’) || isType(s, ‘number’)) { Dom.setStyle(node, t, s); } }; break; case ‘innerhtml’: case ‘text’: if (isType(v, ’string’) && ! v.match(/< .*?>/) && ! v.match(/&.*?;/)) { node.appendChild(document.createTextNode(v)); } else { node.innerHTML = v; } break; default: node.setAttribute(k, v); break; } } }; return node || null; } });
To use this method, simply include it in your JavaScript source files, then call “document.createTag” passing in two parameters: 1st parameter is the tag name you wish to create, and the 2nd is an Object where the keys are tag attribute names and the values are the attribute values. Using a ‘for … in’ loop we iterate on each key in the Object, evaluating only those values that are strings and numbers, or an object in the case of the style attribute. The switch statement then, normalizes the keys, so the key ‘checked’ does the same thing as ‘cHeCkEd’, because capitalization does matter.
Over the years I have added each case of the switch statement based on issues experienced in various browsers. Most attributes seem to be applied just fine, when you use the ’setAttribute’ method, so this is the default case. Some attributes such as ‘checked’ and ‘disabled’ do not work in all browsers with ’setAttribute’, so they are applied only with dot notation. Some attributes such as ‘cellPadding’ and ‘cellSpacing’ are case-sensitive in certain browsers (and capitalizing them doesn’t break the browsers that lower-case worked in), and/or can only be applied via dot notation, so we special-case each of them. The word ‘class’ is a reserved word in at least IE, so you cannot do “object.class”, instead you need to use “object.className”, and this seems to be supported by all browsers; I also support various ways of storing the classname as a key, because different projects have different naming conventions. Style is a special-case that must contain an object, where the keys are style names, and the values are what you want to set the style to (strings and integers are acceptable). Lastly, the ‘text’ or ‘innerhtml’ key will attempt to append the provided value as a text node, unless the value: isn’t a string, contains HTML elements, or contains HTML special characters; in those cases it uses innerHTML, because it will render HTML and special characters correctly, while a text node will simply print the text as is.
Now, this method probably isn’t perfect, but it works with all the browsers that I have ever needed to support. Feel free to chime in, if you know of any other special-case situations or browsers that you believe this method won’t work with.
This solution is homegrown, and there may exist better DOM node creation methods, with more exposure and support. I know the Framework Ext.js has a DOM node creation method, and I wouldn’t be surprised if Dojo or jQuery have a plugin solution as well.

JQuery natively does this by parsing through a string of how you’d write your HTML on the page. Not sure about Dojo, but it’s probably a safe bet that most libraries have some method of doing this.
This struck an idea in me, of a hackish way in which to create a very simple createTag, although, I haven’t tested in extensively. The idea is that you have a hidden div tag with the id “createTag” and a function like this:
function createTag(tagStr) {
}
Comment by MillsJROSS — April 16, 2008 @ 6:03 am
Woops…accidently pressed things…anyway a function like this:
function createTag(tagStr) {
var div = document.getElementById(”createElement”);
div.innerHTML = tagStr;
return createElement.firstChild;
}
The advantage in this being that most of the work is done by the browser, with little code. You just append the tag where you want it. However, as mentioned, I have not fully tested this for browser compatability.
Comment by MillsJROSS — April 16, 2008 @ 6:11 am
Woops again…
return div.firstChild;
or
return div.firstChild.cloneNode(true);
Sorry for the triple post.
Comment by MillsJROSS — April 16, 2008 @ 6:13 am
“The switch statement then, normalizes the keys, so the key ‘checked’ does the same thing as ‘cHeCkEd’, because capitalization does matter.”
switch (k.toLowerCase()) {
…
case ‘checked’:
case ‘disabled’:
node[k] = v;
break;
Would that not be bad, as ‘ChEcKed’ would be caught, but the assignment would end up being node[’ChEcKed’] = v; which, as far as I’m aware, would fail?
Comment by Anonymous — April 20, 2008 @ 7:46 am
You are correct. The variable k should be lower-cased after fetching the value from the hash. I have updated the script above to reflect this change.
Comment by Matt Snider — April 27, 2008 @ 11:01 am