tags:

views:

123

answers:

5

hi,

I'm trying to write a javascript function that adds some DOM nodes to the document in the place it was called, like this:

...
<div>
  <script type="text/javascript">
    pushStuffToDOMHere(args);
  </script>
</div>
...

i try to do it 'cleanly', without using node id property of the div, or innerHTML string manipulation. for that I need to know where in the document the script tag is located. is there a way to do it?

+12  A: 

Talking about cleanly, I don't think your approach is particularly clean. It is a much better idea to give the div a unique id and execute your javascript when the DocumentReady-event fires.

n3rd
and in another file alltogether
Itay Moav
A: 

Not really sure what your trying to achieve but this would pass the dom element to the function when clicked. You could then use jquery in the function to do what you wanted like so

...
<script type="text/javascript">
    function pushStuffToDOMHere(element)
    {
          $(element).append("<p>Hello</p>"); // or whatever
    }
</script>
<div onclick="pushStuffToDOMHere(this);">

</div>
...
Sheff
+3  A: 

Do you have an overriding reason for doing it this way? If not the suggestion to use a unique id makes the most sense. And you can always use a library like jQuery to make this even easier for yourself.

However, the following quick test shows that if you use document.write() in the function then it writes the value into the place where the function was called from.

<html>
<head>
   <script type="text/javascript">
           function dosomething(arg){
              document.write(arg);
           }
   </script>
</head>
<body>
<div>The first Div</div>
 <div>The 
    <script type="text/javascript">
           dosomething("Second");
   </script>
      Div
 </div>
 <div>The
        <script type="text/javascript">
           dosomething("Third");
       </script>
      Div
    </div>
   </body>
</html>

But, again the question, are you sure this is what you want to do?

Vincent Ramdhanie
A: 

my solution is a compbination of the (good) answers posted here:

as the function is called, it will document.write a div with a unique id. then on document.onload that div's parent node can be easily located and appended new children.

I chose this approach because some unique restrictions: I'm not allowed to touch the HTML code other than adding script elements. really, ask my boss...

another approach that later came to mind:

function whereMI(node){
    return (node.nodeName=='SCRIPT')? node : whereMI(node.lastChild);
}
var scriptNode = whereMI(document);

although, this should fail when things like fireBug append themselves as the last element in the HTML node before document is done loading.

Amir Arad
+1  A: 

Although I agree with n3rd and voted him up, I understand what you are saying that you have a specific challenge where you cannot add an id to the html divisions, unless by script.

So this would be my suggestion for inlining a script aware of its place in the DOM hierarchy, in that case:

  1. Add an id to your script tag. (Yes, script tags can have ids, too.)

    • ex. <script id="specialagent" type="text/javascript">
  2. Add one line to your inline script function that gets the script element by id.
    • ex. this.script = document.getElementById('specialagent');
  3. ...And another that gets the script element's parentNode.

    • ex. var targetEl = this.script.parentNode;
  4. Consider restructuring your function to a self-executioning function, if you can.

    • Ideally it executes immediately, without the necessity for an 'onload' call.
    • see summary example, next.

SUMMARY EXAMPLE:

<script id="specialagent" type="text/javascript">
var callMe = function(arg1,arg2,arg3) {
    this.script = document.getElementById('specialagent');
    var targetEl = this.script.parentNode.nodeName=="DIV" && this.script.parentNode;
    //...your node manipulation here...
}('arg1','arg2','arg3');
</script>

The following TEST code, when run, proves that the function has identified its place in the DOM, and, importantly, its parentNode. The test has division nodes with an id, only for the purpose of the test. They are not necessary for the function to identify them, other than for testing.

TEST CODE:

<html>
<head>
<title>Test In place node creation with JS</title>
</head>
<body>
<div id="one">
    <h2>Child of one</h2>
    <div id="two">
            <h2>Child of two</h2>
            <script id="specialagent" type="text/javascript">
            var callMe = function(arg1,arg2,arg3) {
                this.script = document.getElementById('specialagent');
                var targetEl = this.script.parentNode;
                /*BEGIN TEST*/
                 alert('this.script.id: ' + this.script.id);
                 alert('targetEl.nodeName: ' + targetEl.nodeName + '\ntargetEl.id: '+targetEl.id);
                 alert('targetEl.childNodes.length: ' + targetEl.childNodes.length);
                 var i = 0;
                 while (i < targetEl.childNodes.length) {
                     alert('targetEl.childNodes.'+i+'.nodeName = ' + targetEl.childNodes[i].nodeName);
                     ++i;
                }
                /*END TEST - delete when done*/  
                //...rest of your code here...to manipulate nodes
            }('arg1','arg2','etc');
            </script>
     </div>
 </div>
 </body>
 </html>
Fran Corpier
that's a great approach, and the code you used here taught me some nice expression tricks. the next logical step for me is simply using custom tags in the html, and parsing them at the onload event. THANKS!
Amir Arad
Glad to help. A conditional block should, of course, surround the node manipulation. For the above examples, 'If (targetEl){...your code...}'.
Fran Corpier