views:

1878

answers:

3

Instead of tediously search for workarounds for each type of attribute and event when using the following syntax:

   elem = document.createElement("div");
   elem.id = 'myID';
   elem.innerHTML = ' my Text '
   document.body.insertBefore(elem,document.body.childNodes[0]);

Is there a way where I can just declare the entire HTML element as a string? like:

  elem = document.createElement("<div id='myID'> my Text </div>");
  document.body.insertBefore(elem,document.body.childNodes[0]);
+5  A: 

In old school JavaScript, you could do this:

document.body.innerHTML = '<p id="foo">Some HTML</p>' + document.body.innerHTML;

In response to your comment:

[...] I was interested in declaring the source of a new element's attributes and events, not the innerHTML of an element.

You need to inject the new HTML into the DOM, though; that's why innerHTML is used in the old school JavaScript example. The innerHTML of the BODY element is prepended with the new HTML. We're not really touching the existing HTML inside the BODY.

I'll rewrite the abovementioned example to clarify this:

var newElement = '<p id="foo">This is some dynamically added HTML. Yay!</p>';
var bodyElement = document.body;
bodyElement.innerHTML = newElement + bodyElement.innerHTML;
// note that += cannot be used here; this would result in 'NaN'

Using a JavaScript framework would make this code much less verbose and improve readability. For example, jQuery allows you to do the following:

$('body').prepend('<p id="foo">Some HTML</p>');
Mathias Bynens
Anyway to do this without a framework?
Jenko
Sure, check the edit.
Mathias Bynens
Pretty good. But I was interested in declaring the source of a new element's attributes and events, not the innerHTML of an element.
Jenko
Perhaps my latest edit will make things more clear.
Mathias Bynens
Can I use "document.body" instead of "document.getElementsByTagName" ?? Wouldn't it be more backward compatible?
Jenko
`document.getElementsByTagName('body')[0]` can indeed be replaced by `document.body`, good point. However, if you want to prepend or append the new HTML to another existing element instead of the BODY, you'll have to use `document.getElementById()` and/or `document.getElementsByTagName()`; that's why I used it in the example.
Mathias Bynens
$('body').insertBefore('<p id="foo">Some HTML</p>') won't work. You're not inserting the <body> before the <p>!!???
J-P
Also, your code can get very messy very quickly if you're directly adding/inserting "innerHTML"
J-P
I must've overlooked that one, JimmyP. Thanks! It's fixed now.
Mathias Bynens
@JimmyP: What rubbish! The very purpose of this question is to be able to directly insert HTML as strings instead of playing around with functions to construct it, attrib by attrib, node by node, element by element.
Jenko
jeremy, it's not rubbish; check out my abstraction below. All this needs is some polishing - I am not saying don't use innerHTML.
J-P
@JimmyP: I meant your point about "gets messy" is rubbish, since I *want* to edit/see the "raw" HTML!.
Jenko
this detaches all event handlers and may cause memory leaks big time.
adardesign
+2  A: 

Instead of directly messing with innerHTML it might be better to create a fragment and then insert that:

function create(htmlStr) {
    var frag = document.createDocumentFragment(),
        temp = document.createElement('div');
    temp.innerHTML = htmlStr;
    while (temp.firstChild) {
        frag.appendChild(temp.firstChild);
    }
    return frag;
}

var fragment = create('<div>Hello!</div><p>...</p>');
// You can use native DOM methods to insert the fragment:
document.body.insertBefore(fragment, document.body.childNodes[0]);

Benefits:

  1. You can use native DOM methods for insertion such as insertBefore, appendChild etc.
  2. You have access to the actual DOM nodes before they're inserted; you can access the fragment's childNodes object.
  3. Using document fragments is very quick; faster than creating elements outside of the DOM and in certain situations faster than innerHTML.


Even though innerHTML is used within the function, it's all happening outside of the DOM so it's much faster than you'd think...

J-P
I bet this createDocumentFragment() wouldn't be as good as the "legacy" innerHTML.
Jenko
I really would like backward compatibility, so how could I use this alongside innerHTML, like I check if this method is not null, maybe?
Jenko
This method works in all modern browsers. For IE 5.5 and below you could perform a check like:: if (document.createDocumentFragment) { create('...'); } else { /* Use innerHTML perhaps */ }
J-P
Exactly my point, thanks for the code snippet! I like your method since its quick, so making this the default behavior on all modern browsers is preferable.
Jenko
Marked as accepted since its the fastest and .. lightest; no dep on frameworks.
Jenko
Booo. All kinds of fail on the likes of mySelect.appendChild(create('<option>Two</option>')) or myTable.tBodies[0].appendChild(create('<tr><td>3.1</td><td>3.2</td></tr>'))
Crescent Fresh
crescentfresh - anomalies... In 99% of cases it won't fail; where it does you'll have to venture another abstraction.
J-P
Double boo. Devs on here don't care that your function works for 99% of all inputs. They care that it works for 100% of *their* inputs. And in every AJAX app I've ever touched appending data to tables and populating drop downs account for a hell of a lot more than 1%.
Crescent Fresh
crescentfresh, I help on SO because I enjoy helping people; I'm sorry if a solution is not 100% operable in all situations. If you're so concerned why not offer your own solution instead of being unnecessarily critical of already-offered answers? With any abstraction there will always be edge-cases! This is a learning environment - we're not here to give people a solution on a plate - we're here to help each other become better at what we do! And sorry, but where did anyone mention "AJAX"?
J-P
Fair enough. My apologies. I just feel that there're so many abstractions on here with zero caveats mentioned.
Crescent Fresh
+1  A: 

The above answers are great, another approach would be to use Jquery (not worth it just for this but you may find it useful in many other ways):

$("body").prepend("<div id='myID'> my Text </div>");

Lovely, isn't it?

larson4
Hey mister, the jQuery method has already been posted above, in the "accepted" answer, and was as a matter of fact the first reply to this question!
Jenko
Oops, somehow I missed that...
larson4