tags:

views:

1112

answers:

4

Update: I just narrowed my problem to this:

Why doesn't this work:

var tmp = document.createElement('tbody');
tmp.innerHTML="<tr><td>hello</td></tr>";

tmp is getting the string hello. the tr and td html is lost (on FireFox). Why is that? and how can I make such html injection work?

Original question:

I need to inject arbitrary HTML after a arbitrary element in arbitrary HTML documents. I came across this method (inject the html string into dynamically generated div, get its firstchild element and insert it in the right place):

var tmp = document.createElement('div'); 
tmp.innerHTML = _injected_html;
var new_w = tmp.firstChild;
var parent = insertion_point.parentNode;
parent.insertBefore(new_w, insertion_point.nextSibling);

The problem is that this does not work when trying to inject table elements. if the injected html is for example

"<tr> <td> table data </td> </tr>"

The _tmp.innerHTML = _injected_html; would not accept it (adding tr under div element).

Any idea how to make this work for any tag?

+2  A: 

Are you testing in IE by any chance? Most likely it does work in other browsers.

Here's why

edit: Wait, you're inserting something into the table that looks like <div><tr><td>... that's not going to work. Why don't you replace the document.createElement('div') by document.createElement('tr'), and remove the <tr> tags from the _injected_html?

Something like this (tested in Firefox):

<script>
var i = 3;

function f() {
    var table = document.getElementById('someTable');
    var children = table.children[0].children;
    var after = children[Math.round(Math.random() * (children.length - 1))];
    var html = "<td>" + i++ + "</td>";

    g(html, after);
}

function g(_injected_html, insertion_point) {
    var tmp = document.createElement('tr'); 
    tmp.innerHTML = _injected_html;
    var new_w = tmp.firstChild;
    var parent = insertion_point.parentNode;
    parent.insertBefore(new_w, insertion_point.nextSibling);
}
</script>

<table id="someTable" onclick="f();">
    <tr><td>1</td></tr>
    <tr><td>2</td></tr>
</table>

The second line of f() is a little awkward, but it gets the first child of the table (which is a <tbody>, and then its children (the actual <tr>s).

Aistina
testing on FF at this point. Final solution should be completely cross browser
Nir
nice catch, do you know what IE versions are affected by any chance?
roe
A: 
<div><td><lol/>

..isn't valid HTML! Containers are required for table rows/cols/heads, list items, definition lists and so on. Could you somehow validate the HTML for proper containers before injecting it?

Al
A: 

The following javascript will allow you to inject HTML/etc into the local page:

var example = "<p>test</p>"
document.body.appendChild(example);

That said, you will have to customize the code depending on what you are inserting.

OMG Ponies
A: 

For a table, you must insert tr's into tbody. When you write html

<table><tr><td>abc</td></tr></table>

IE, FF, Chrome, Safari at least (don't know about others directly) will modify this to be:

<table><tbody><tr><td>abc</td></tr></tbody></table>

Therefore, something like:

var tmp = document.createElement('tr'); 
tmp.innerHTML = "<td>def</td>";
var new_w = tmp.firstChild;
var parent = insertion_point.parentNode;
parent.insertBefore(new_w, insertion_point.nextSibling);

if insertion_point is a tr tag.

But honestly, with Jquery there are more elegant ways of going about this as christina toma notes.

larson4
Thanks! Please see the update above. I don't think this is the problem. (+ I can't use jquery)
Nir