4
<div>
HI!
<script>
var spanNode = document.createElement('span');
var textNode = document.createTextNode('there.');
//how to append here spanNode?
</script>
How are you?
</div>

I don't want to use document.write() method. So, what should I use here so the result would be like this:

<div>HI!<span>there.</span>How are you?</div>
Navin Rauniyar
  • 10,127
  • 14
  • 45
  • 68

2 Answers2

7

A <script> element by default is executed immediately, so at the moment of execution there's just <div>HI! <script /> in the document, the "How are you" part hasn't been processed yet. At this moement the currently processed <script> element will be the last of script elements in your document so you can reference it using document.scripts[ document.scripts.length - 1 ], then find its parent node and append the elements.

<div>
HI!
<script>
var spanNode = document.createElement('span');
var textNode = document.createTextNode('there.');
    spanNode.appendChild( textNode );
/* this is the currently interpreted <script> element
   so you can append a child to its parent.
*/
document.scripts[ document.scripts.length - 1 ].parentNode.appendChild( spanNode );
</script>
How are you?
</div>

http://jsfiddle.net/0LsLq9x7/

Edit: to keep the global namespace clean you could wrap the code in an anonymous function which executes immediately: http://jsfiddle.net/0LsLq9x7/1/

<div>
HI!
<script>
(function( scriptElement ){
    // these variables will be local to this closure
    var spanNode = document.createElement('span');
    var textNode = document.createTextNode('there.');
    spanNode.appendChild( textNode );
    scriptElement.parentNode.appendChild( spanNode );
// pass a reference to the script element as an argument to the function
}(document.scripts[ document.scripts.length - 1 ]));
</script>
How are you?
</div>
pawel
  • 35,827
  • 7
  • 56
  • 53
  • That's correct way to do it. @NavinRauniyar Since browser renders one element at a time (and since script is not `deferred/async`) by the time `scipt` tag is visited it is guarantied that this is the **last** script tag. So `document.scripts[ document.scripts.length - 1 ]` selects current script. – dfsq Dec 15 '14 at 09:56
  • @NavinRauniyar added an explanation in the answer, but the currently processed script is the last script in the document, because the rest hasn't been loaded yet :) (doesn't apply to deferred / async scripts). – pawel Dec 15 '14 at 09:58
  • I used this code and no matters where the script tag in document but works great. Thank you. – Navin Rauniyar Dec 15 '14 at 10:00
  • @dfsq what if used defer="defer" ? – Navin Rauniyar Dec 15 '14 at 10:29
  • @pawel I'm still unclear with the code. How is it appending right after the script tag? – Navin Rauniyar Dec 15 '14 at 10:33
  • @NavinRauniyar Then proper result is not guarantied. – dfsq Dec 15 '14 at 10:34
  • For this problem this is a good solution. But there are problems with this approach if the script contains asynchronous functions (like Ajax). Aslo this doesn't work if the script is added dynamically.. http://stackoverflow.com/questions/403967/how-may-i-reference-the-script-tag-that-loaded-the-currently-executing-script – Sampath Liyanage Dec 15 '14 at 10:40
  • @plbsam the second solution will work with AJAX with a minor tweak, using `insertBefore` instead of `appendChild`: http://jsfiddle.net/0LsLq9x7/3/ (using `setTimeout` for async execution, but the same applies to ajax callback). – pawel Dec 15 '14 at 11:11
  • @pawel Ah. Good to know that. I just referenced something I found. I think what it meant was, document.scripts couldn't be used inside callbacks... Btw why did you use a temporary scoop? Is it necessary? http://jsfiddle.net/0LsLq9x7/4/ – Sampath Liyanage Dec 15 '14 at 11:29
  • @plbsam like I said - to keep the variables from polluting the global scope. – pawel Dec 15 '14 at 11:49
0

You can first get the current script. Then add the element before (or after) the script..

<div>
HI!
<script id="myscript">
var spanNode = document.createElement('span');
var textNode = document.createTextNode('there.');
    spanNode.appendChild( textNode );
  
    //appending the span node
    var ele = document.currentScript;   //get current script element
    ele.parentNode.insertBefore(spanNode,ele);  //append the span before the script
</script>
How are you?
</div>
Sampath Liyanage
  • 4,776
  • 2
  • 28
  • 40