innerHTML and SCRIPT tag
Question posted by: PJ (Guest) on July 19th, 2006 02:35 PM
Greetings...
I have stumbled upon a small problem.
I use Ajax to retrieve part of a page I need to update. I update a DIV
element with the HTML contents I get from another page.
It works fine.
However the HTML have a SCRIPT tag that the browser should process, but
it doesn't.
Here's an example:
--- pageX.aspx ---
<table>
<tr>
<td>Table 01</td>
</tr>
</table>
<script>
alert("HI");
</script>
--- end pageX.aspx ---
--- page on browser ---
<div id="divContents"></div>
<script>
divContents.innerHTML = getHtmlFromPage("pageX.aspx");
</script>
--- end page on browser ---
When the prowser gets the "pageX.aspx" and updates the contents of the
'divContents' it displays the table, but it didn't process the script.
What am I doing wrong?
Regards,
PJ
http://pjondevelopment.50webs.com
Deliver bug-free source code. Download whitepaper from Coverity.
Create Complex Scripts in Minutes! No Code. Download Free Trial Now.
www.NetworkAutomation.com/Scripting
PrimalScript 2007 Enterprise PowerShell and Vista support
Randy Webb Guest n/a Posts | July 19th, 2006 |
Re: innerHTML and SCRIPT tag
PJ said the following on 7/19/2006 10:43 AM:
Quote: Greetings... |
It works in IE, it won't work in any other browser since you are relying
on an IE-shortcut to get a reference to the div tag.
Quote: However the HTML have a SCRIPT tag that the browser should process, but |
Script blocks inserted via innerHTML don't get executed in any browser
other than NS6
<snip>
Quote: When the prowser gets the "pageX.aspx" and updates the contents of the |
You will have to search through your HTML block and find the script
elements and insert them using createElement to get the script blocks
executed.
var d =
document.getElementById('divContents').getElements ByTagName("script")
var t = d.length
for (var x=0;x<t;x++){
var newScript = document.createElement('script');
newScript.type = "text/javascript";
newScript.text = d[x].text;
document.getElementById('divContents').appendChild (newScript);
}
--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Temporarily at: http://members.aol.com/_ht_a/hikksnotathome/cljfaq/
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
petermichaux@gmail.com Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
Randy Webb wrote:
Quote: You will have to search through your HTML block and find the script |
I haven't seen this method before. I've been taking another approach
that uses eval and wonder if one way is superiour (faster, more robust
etc).
function update(element, html) {
document.getElementById(element).innerHTML=html;
var re = /<script\b[\s\S]*?>([\s\S]*?)<\//ig;
var match;
while (match = re.exec(html)) {
eval(match[1]);
}
};
Thanks,
Peter
Richard Cornford Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
Join Bytes! wrote:
Quote: Randy Webb wrote:
|
They are not equivalent so comparison is irrelevant. If you - eval -
code - var - will create function local variables instead of global ones
and function declarations will be inner functions not global ones.
Richard.
Randy Webb Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
Join Bytes! said the following on 7/19/2006 8:27 PM:
Quote: Randy Webb wrote:
|
Yes, one way is superior to the other. You can read Richard's reply for
an explanation of the scope issues involved with the eval portion.
Second. Where is your script block appended? And, how would you go about
removing it? With the above code, you can simply set the innerHTML of
divContents to '' and you have removed *all* script blocks that were
appended. Meaning, when a new request is made, you are not retaining all
of your old script blocks but they are discarded.
And that is not even getting into the aspects of eval.
--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Temporarily at: http://members.aol.com/_ht_a/hikksnotathome/cljfaq/
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
petermichaux@gmail.com Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
Second. Where is your script block appended?
If I do
var d = document.getElementById('my_div');
d.innerHTML = htmlInAjaxResponse;
and htmlInAjaxResponse has script blocks in it, then are the script
blocks not inside "my_div"? If not where are they? If so then will they
not be removed when I use d=''; ?
Thanks,
Peter
Randy Webb Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
Join Bytes! said the following on 7/19/2006 10:14 PM:
Quote:
|
The code for them is, the code that got executed, and its scope, is not.
Quote: If not where are they? If so then will they not be removed when I use d=''; ? |
There is a difference between the code you read in and execute (it's
source) and the code that is actually executed, along with it's scope chain.
Besides, even if they are exactly the same results (they aren't always),
the first *has* to be more efficient since it isn't starting up the
parser every time you eval something.
--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Temporarily at: http://members.aol.com/_ht_a/hikksnotathome/cljfaq/
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Jim Davis Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
"Randy Webb" <HikksNotAtHome@aol.comwrote in message
news:3PWdneRKq-IMDiPZnZ2dnUVZ_tidnZ2d@comcast.com...
Quote: PJ said the following on 7/19/2006 10:43 AM:
|
*snip*
Quote:
|
One wrinkle to this.
IE will parse/execute a script block injected into a DIV - however you must
first set the innerHTML property to "null" THEN load the content as in:
document.getElementById(ElementID).innerHTML = null;
document.getElementById(ElementID).innerHTML = NewContent;
I've not (yet?) been able to get FireFox to do the same thing (at least not
without the kind of DOM parsing you mention).
I use the above extensively in a windowing system for intranet applications
(although this works in a normal HTML file we use it in corporate HTA
applications).
Jim Davis
Jim Davis Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
"Jim Davis" <newsmonkey@vboston.comwrote in message
news:drydnTkVQvfT6iLZnZ2dnUVZ_tCdnZ2d@giganews.com ...
Quote: "Randy Webb" <HikksNotAtHome@aol.comwrote in message
|
Actually I've fibbed a little. More information:
To get the injected script to actually run in IE you also need to set the
"defer" attribute on the script element to "defer" as in:
<script type="text/javascript" defer="defer">
alert("My Script's a runnin'!");
</script>
So to just let injected script run (in IE) you need to just set the "defer"
attribute.
Setting the innerHTML to null is not actually required to run the script
however it's still a VERY good idea. The reason is because IE will not
automatically over-write any existing functions unless you do this. Setting
the innerHTML to null actually unloads all functions defined in the
DIV-contained script elements and allows new ones of the same name(s) to be
created.
For example if you had a function called "Init()" in multiple pieces of
content IE would always run the first instance loaded into the DIV UNLESS
you "null" the container before loading the subsequent block.
The "pages" in my applications (all content retrieved via an XMLHttpRequest
call and injected into a DIV ) all reference a created psuedo-scope called
"Page" and have certain standardized functions ("Page.Init()" which
initilizes the page, "Page.Denit()" which run when the page is unloaded and
"Page.Renit()" which is run when the page is resurfaced but not reloaded).
The nulling of the container DIV is neccessary to allow the replacement
functions to be properly added to the model.
Jim Davis
Jim Davis Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
"Jim Davis" <newsmonkey@vboston.comwrote in message
news:MKadnY3harDnOSLZRVn_vQ@giganews.com...
Quote: > |
Oh - one other imprtant thing: if you set the injected script to "defer"
then FireFox will run it as well... but it has other troubles with
overwriting functions.
Still if you just plain want to run an "alert()" like the OP then "defer"
seems to be your friend.
Jim Davis
Jim Davis Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
"Jim Davis" <newsmonkey@vboston.comwrote in message
news:QdudnYi9jZTpNSLZRVn_vQ@giganews.com...
Quote: >
|
One last thing (well.. maybe not since you guys got me thinking about this):
Remember that "defer" has other aspects to it. In this arena the main issue
to worry about is that "defer" essentially instructs the agent that this
block of script will not generate inline content (no "document.write()"
statements).
So while it seems that you can use "defer" to inject script into IE and
Firefox (with caveats) you can't use it to inject ALL script. Any inline
code generation will really foul things up in both IE and Firefox (the
entire current document is thrown away and replaced with the newly generated
content).
This isn't at all "wrong" or unexpected if you know what "defer" actually
does but might be a suprise to the unaware.
Jim Davis
Richard Cornford Guest n/a Posts | July 20th, 2006 |
Re: innerHTML and SCRIPT tag
Jim Davis wrote:
Quote: Jim Davis wrote: |
<snip>
Quote:
|
<snip>
Quote: Setting the innerHTML to null is not actually required |
I am glad you backtracked on this as assigning null to innerHTML really
looked like 'mystical incantation' programming. In principle the null
would be type-converted into the string 'null', which should have no
special significance when inserted with innerHTM, and if the desire was
to empty the contents of the element prior to assigning new innnerHTML
it would be more reasonable to be assigning an empty string than null.
Quote: to run the script however it's still a VERY good idea. |
<snip>
That doesn't appear to be true when tested in IE 6 with:-
<html>
<head>
<title></title>
<script type="text/javascript">
var count = 0;
function runTest(){
var div = document.getElementById('t1');
div.innerHTML = 'x<script type="text/javascript" defer>'+
'function s(){return '+(++count)+';}<\/script>';
alert(window.s);
}
function runTest2(){
var div = document.getElementById('t1');
div.innerHTML = null;
alert(window.s)
}
</script>
</head>
<body>
<div id="t1"></div>
<input type="button" onclick="runTest();" value="Load Script">
<input type="button" onclick="runTest2();" value="null innerHTML">
</body>
</html>
- where, say, pressing the "Load Script" repeatedly wihtout pressing the
"null innerHTML" button shows the numbr in the disapyed source for the -
s - fucntion incermenting (so each previous version must have been
replaced), and subsequanty pressing the "null innerHTML" button shows no
eveidence of the current - s - fuction being influenced in any way. So
no unloading of "all functions defined in the DIV-contained script
elements".
This suggests that you have acquired a misconception about what is
happening in IE. It might be an idea to try backing future assertions on
this subject up with code that demonstrates the phenomena you assert so
that people can point out the sources of any further misconceptions.
Richard.
Randy Webb Guest n/a Posts | July 21st, 2006 |
Re: innerHTML and SCRIPT tag
Jim Davis said the following on 7/20/2006 11:42 AM:
Quote: "Jim Davis" <newsmonkey@vboston.comwrote in message
|
Actually, it was a lot, not a little.
Quote: More information: |
Or extract the text of the script element, re-create it and you are done
in any browser that supports createElement and appendChild
Quote: Setting the innerHTML to null is not actually required to run the script |
No, it's not. As Richard pointed out, but even then it's a moot point.
Quote: The reason is because IE will not automatically over-write any |
I don't believe that.
Quote: Setting the innerHTML to null actually unloads all functions defined in the |
I don't believe that either.
Quote: For example if you had a function called "Init()" in multiple pieces of |
That is about as far from true as you can get.
Quote: The "pages" in my applications (all content retrieved via an XMLHttpRequest |
The "pages" have something else in them that is screwing it up then. Or,
you have a completely broken version of IE.
Quote: The nulling of the container DIV is neccessary to allow the replacement |
Only if you have something else causing it. Probably from relying on
some voodoo incantation using innerHTML instead of something more
reliable to trigger your code.
--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Temporarily at: http://members.aol.com/_ht_a/hikksnotathome/cljfaq/
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
petermichaux@gmail.com Guest n/a Posts | July 21st, 2006 |
Re: innerHTML and SCRIPT tag
Randy Webb wrote:
Quote:
|
Is NS6 likely the reason that Prototype.js has a update() function that
first strips the scripts like shown in the followng snips. Is stripping
the scripts worthwhile as NS6 must be fairly old by now?
ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
stripScripts: function() {
return this.replace(new RegExp(Prototype.ScriptFragment, 'img'),
'');
},
update: function(element, html) {
$(element).innerHTML = html.stripScripts();
setTimeout(function() {html.evalScripts()}, 10);
},
Why do you think there is a setTimeout() before evaluating the scripts?
Disclaimers:
* I would ask the author if I thought he was a reliable source of
JavaScript coding. I don't so I am appealing to c.l.j. collective
wisdom.
* I don't want to use Prototype.js but I do need to understand it if I
am going to replace parts of it for my use with Rails.
Thanks,
Peter
Randy Webb Guest n/a Posts | July 21st, 2006 |
Re: innerHTML and SCRIPT tag
Join Bytes! said the following on 7/20/2006 9:26 PM:
Quote: Randy Webb wrote:
|
I highly doubt it.
Quote: Is stripping the scripts worthwhile as NS6 must be fairly old by now? |
It isn't simply "stripping the scripts". What it should be doing is
reading the text of the script elements and creating new script elements
with the text so that they get executed reliably.
Quote: Why do you think there is a setTimeout() before evaluating the scripts? |
Probably to keep from locking up the browser on a script block intensive
set of code.
Quote: Disclaimers: |
If you want to know how to cause script blocks to be executed when
inserted in a page via innerHTML, then clj is the best place to ask.
Quote: * I don't want to use Prototype.js but I do need to understand it if I |
You would do better off by replacing all of it for use with anything.
--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Temporarily at: http://members.aol.com/_ht_a/hikksnotathome/cljfaq/
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
Jim Davis Guest n/a Posts | July 21st, 2006 |
Re: innerHTML and SCRIPT tag
"Richard Cornford" <Richard@litotes.demon.co.ukwrote in message
news:e9p0je$dss$1$830fa17d@news.demon.co.uk...
Quote: Jim Davis wrote:
|
Quote: >snip< |
Quote:
|
Yeah... I built a striupped dowqn version to test myself (but can't post
from the office).
However I think I may dig deeper... I pride myself on commenting and it's
clearly commented in the system. But I built the original system in IE 5
which unfortunately I don't have readily available.
Quote: This suggests that you have acquired a misconception about what is |
Misconception acquired, identifed and eliminated.
Jim Davis
Jim Davis Guest n/a Posts | July 21st, 2006 |
Re: innerHTML and SCRIPT tag
"Randy Webb" <HikksNotAtHome@aol.comwrote in message
news:n7qdnfkA1IcJt13ZnZ2dnUVZ_vGdnZ2d@comcast.com. ..
Quote: Jim Davis said the following on 7/20/2006 11:42 AM:
|
Quote: >snip< |
Quote:
|
Well... I _thought_ it was a little. Turned out it was a lot. ;^)
Quote:
|
Of course your solution has one caveat...
IE will run the code as is using "defer", Firefox will not. Using just the
script recreation code you posted with "defer" will actually run the code
TWICE in IE.
You can simply run the script without "defer" of course - and this is by far
the simplest method, but you are doing work not required by IE. If you've
got a lot of code then you may want to make the decision to do a bit more
complex and only run the script recreation in Firefox and not in IE.
Also note that, as is, your code will actually create duplicate script
blocks (dump the contents of the DIV to see this). I would take the effort
to remove the original code blocks. Adding a line like the following within
your loop should do it I think:
d[x].parentNode.removeChild(d[x]);
In initial tests this seems to work fine. I would have liked to simply
replace the original blocks with the new blocks but I couldn't discover a
method that would both replace the block AND run it.
Quote:
|
Well I can get much, MUCH farther from "true" but that's beside the point.
;^)
As I noted when falling on my sword with Richard after testing it I
discovered that I was indeed wrong. I'm going to do a little more digging
since I wrote the original code under IE 5 and I can't test that readily.
I'm generally pretty anal about commenting all "odd" things and this has a
large, elborate comment concerning the need to "null" the container.
Even if I'm wrong I'm curious how I came to the conclusion. It may be for
some other reason and I'm misrembering. In any case I'm definately wrong
concerning IE 6.x.
Oh... one more aspect of this when injecting script into DIVs to simulate
new "pages".
Injecting the script element is all well and good, but as we've seen doing
so is the same as running that script globally: replacing the content of the
DIV does not (as you and Richard have pointed out) eliminate script
declaration previously made regardless of the content of the DIV. Functions
set, global variables declared, etc will persist unless explicitly
overridden.
Automatically "knowing" or discovering which declarations were made by the
script blocks in question could be nightmarishly difficult.
To address this, as I mentioned before, you can create a container for the
page-specific material - a sort of pseudo-scope. Create, for example, a
global object called "Page" and place all of your page specific functions,
variables, etc within it.
For example:
Page = new Object();
Page.myVar = value;
Page.Init = function() {};
.... and so forth.
If each "page" loaded reinitializes that "scope" object (or, better, a
global page loader method manages it) then you'll be reducing the amount of
"baggage" left around as pages are loaded and the application is used.
Jim Davis
Randy Webb Guest n/a Posts | July 21st, 2006 |
Re: innerHTML and SCRIPT tag
Jim Davis said the following on 7/20/2006 11:56 PM:
Quote: "Randy Webb" <HikksNotAtHome@aol.comwrote in message
|
<snip>
Quote:
|
If I were writing code for production use, it wouldn't have that caveat
but you are right.
Quote: IE will run the code as is using "defer", Firefox will not. Using just the |
Then leave the defer out, create your own element, then you have nothing
to worry about.
Quote: You can simply run the script without "defer" of course - and this is by far |
But by including the defer you are creating double work for yourself.
Quote: If you've got a lot of code then you may want to make the decision to |
Run the script recreation in both, simple solution to a simple problem.
Don't fall into the trap of trying to make it more difficult than it is.
Quote: Also note that, as is, your code will actually create duplicate script |
Yes, and I didn't write production code. I wouldn't use either method to
be honest with you in real time production code.
Quote: In initial tests this seems to work fine. I would have liked to simply |
You won't. And that leads to a potential flaw in the entire process.
Retrieve this simple document using this new fangled technology called
"AJAX", read the script block, execute it, then view source.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
"http://www.w3.org/TR/REC-html40/strict.dtd">
<html>
<head>
<title>Input Questions</title>
</head>
<body>
<script type="text/javascript">
document.write('My name is Fred Flintstone');
</script>
</body>
</html>
Back to the drawing board Barney :)
And the problem will occur with any script block that uses
document.write to create content when it is retrieved, parsed, and executed.
<snip>
Quote: As I noted when falling on my sword with Richard after testing it I |
It may be that IE5.0 has some idiotic flaw in it that requires the null
or '' to the container. If it does, that is just one more reason *not*
to depend on defer and innerHTML to execute them.
The backwards compatibility not withstanding, then is one of the reasons
that I have said for almost a year now that I don't use AJAX in a real
world site because I know of a better, simpler, method to do what people
are calling "AJAX" that is more reliable and more widely supported.
Quote: Even if I'm wrong I'm curious how I came to the conclusion. It may be for |
See above.
Quote: Oh... one more aspect of this when injecting script into DIVs to simulate |
It's not an "aspect", its a misunderstanding.
Quote: Injecting the script element is all well and good, but as we've seen doing |
No, it will persist until nothing points to it anymore. Garbage
Collection is your friend
Quote: Automatically "knowing" or discovering which declarations were made by the |
I don't see a reason to need to know except when debugging. And yes, it
would become a nightmare.
Quote: To address this, as I mentioned before, you can create a container for the |
Probably. But I don't use the HTTPRequest Object to retrieve files for
the "speed" aspect of "Web 2.0" that uses what is called "AJAX". I use a
more reliable, more cross-browser, method that has it's own quirks but
it doesn't have near as many as HTTPRequest does.
--
Randy
comp.lang.javascript FAQ - http://jibbering.com/faq & newsgroup weekly
Temporarily at: http://members.aol.com/_ht_a/hikksnotathome/cljfaq/
Javascript Best Practices - http://www.JavascriptToolbox.com/bestpractices/
|
No comments:
Post a Comment