Insert in place without document.write
So here’s the situation: you want to syndicate some content using JavaScript to pull in the data (like AdWords or similar programs). The syndication script can’t know anything about the page it’s being used on — so it can’t have a dependency on the existence of particular elements. Yet the host page needs to be able to control where the content is inserted — the syndication script needs to insert the content wherever the <script>
tag is.
How do you do it?
Well you probably do what Google does and use document.write
. But document.write
is not a nice technique, it has some notable issues:
document.write
does not work in XHTML mode (on XHTML pages served as XML)- content written in with
document.write
may not subsequently appear in the page’s DOM, which means no further access to manipulate it programmatically, and no access to accessibility APIs document.write
is conceptually wrong because it treats nodes as serialized text — which they’re not — they’re nodes
But what’s the alternative? DOM creation techniques need an existing element reference to work with; even innerHTML
needs to know where to write the HTML. And in both cases, simply appending to <body>
is not an option if you want the new content to appear inline with the existing content.
I was faced with this dilemma a few days ago, until an obvious solution dawned on me — we do in fact have a predictable refence: the <script>
element itself!
All we need is a way of identifying the including <script>
in the DOM, and then we can use the insertBefore
method to append new HTML directly before it.
So, given a syndication script with a fixed ID:
<script type="text/javascript" id="syndication" src="syndication.js"></script>
We can go from oldskool nastiness like this:
document.write('<p id="syndicated-content">Here is some syndicated content.</p>');
To modern loveliness like this:
var newcontent = document.createElement('p');
newcontent.id = 'syndicated-content';
newcontent.appendChild(document.createTextNode('Here is some syndicated content.'));
var scr = document.getElementById('syndication');
scr.parentNode.insertBefore(newcontent, scr);
We could even go a step further and remove the <script>
ID, but in that case we would need a concrete method for identifying the specific element. We could do that by knowing its SRC
:
var scripts = document.getElementsByTagName('script');
for(var i=0; i<scripts.length; i++)
{
if(scripts[i].src == 'http://www.mydomain.com/syndication.js')
{
//scripts[i] is the one
break;
}
}
And there you have it – a simple but elegant way of inserting content in place, removing the last vestige of need for document.write
!