PDA

View Full Version : DOM Reload?



Beagle72
07-04-2010, 04:27 AM
I've got an issue that really has me stumped. Rather than post my long convoluted code, I've put 2 test pages together that really illustrate my problem. They're as short as possible while still being able to duplicate the issue. I've posted these files on one of my servers, so you can see the issue live.

File 1: http://www.vampirerave.com/rave_wars/test/test1.php
File 2: http://www.vampirerave.com/rave_wars/test/test2.php

File 1 pulls data from file 2 via Ajax at 3 second intervals. However, it's only 'half working'.

Here's the code:

File 1:

<html>
<head>
<script type="text/javascript">
function testFunction(){
var http;
var url = "http://www.vampirerave.com/rave_wars/test/test2.php";
try { http = new XMLHttpRequest(); }
catch (e) {
try { http = new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e) {
try { http = new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e) {
alert("Please update your browser.");
return false;
}
}
}
http.open("GET", url, true);
http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
document.getElementById('myDiv').innerHTML+=http.responseText;
}
}
http.send(null);
http.close;
setTimeout("testFunction()",3000);
}
window.onload=function(){
testFunction();
}
</script>
</head>
<body>
<div id="myDiv">
Starting...<br /><br />
</div>
<body>
</html>

File 2:

Hello World!<br /><br />
<script type="text/javascript">
var myDate = new Date();
document.write('The date is: ' + myDate + '<br /><br />');
</script>

As you can see, Hello World is being pulled and displayed just fine. However, the javascript doesn't execute. If you load file 2 directly, the javascript executes just fine and displays the date.

Firebug isn't throwing any errors with either page. I'm guessing this has something to do with the DOM, but I have no idea how to fix it. The issue persists across all browsers, so I know it's not a browser-related issue.

Any help is greatly appreciated as I have been struggling with this all day.

jscheuer1
07-04-2010, 07:31 AM
Scripts on AJAX imported pages generally do not execute.

The thing is, if you imported that page and its script ran, that document.write() bit would overwrite the existing page. The script cannot run until it's imported because javascript cannot run without the browser, and the browser cannot 'see' the page until its content is loaded into (in this case) file 1.

You could use PHP to get the date:

File 2:

Hello World!<br /><br />
<?php
echo 'The date is: ' . date("D M d Y H:i:s \G\M\TO (T)");
?>

But this will be the server time, not the user's time as would be the case with javascript. The above would output something like so:


Hello World!

The date is: Sun Jul 04 2010 07:10:28 GMT+0000 (UTC)

My server is UTC, yours may be as well, either that or the timezone of its locale, or the locale it mostly services, or wants to look like it services.

You could use javascript as part of the onreadystatechange function to insert the date into the fetched content.

Or you could investigate a library like jQuery where scripts can be fetched. This would be different than what you are doing, but a script could be fetched to place the javascript date somewhere on the page.

MooTools has an interesting option with its AJAX function:

http://mootools.net/docs/core/Request/Request


evalResponse - (boolean: defaults to false) If set to true, the entire response will be evaluated. Responses with javascript content-type will be evaluated automatically.

I'm not sure what this does. Even if it executes the script, it will not get you what you want either (because of the document.write() bit). Perhaps with a different script.

Beagle72
07-04-2010, 08:24 AM
Well, the date thing and the contents of file 2 was just a simple way to illustrate the issue. In my actual application 'file 2' is a DHTML menu that dynamically changes based on certain events. It's an Ajax/Comet setup, and I can't get the DHTML to work when it's refreshed. It works fine on first load, but not on subsequent reloads.

I don't think there's a PHP solution here because it's a dynamic DHTML menu that I'm trying to import. This is also a project in development, and there are other issues like this on the horizon (so I'm trying to get ahead of it now). The project it Ajax/Comet/javascript heavy.

I've never worked with jQuery or mootools, but I'll look into them and see if either might solve the problem.

Thanks for your suggestions.

jscheuer1
07-04-2010, 08:49 AM
Your best bet might be combining PHP and javascript. PHP will execute as the server is fetching the content, javascript generally will not execute, but you can invoke javascript as part of your onreadystatechange function, something like:


http.onreadystatechange = function() {
if(http.readyState == 4 && http.status == 200) {
document.getElementById('myDiv').innerHTML+=http.responseText;
//javascript to run against the newly imported content can go here.
}
}

Also, with jQuery you can set up events 'live'. That way they will fire on imported content, even though they are set before the content arrives.

molendijk
07-04-2010, 05:18 PM
You can force scripts on AJAX imported pages to execute by document.writing the external pages containing the scripts into a hidden div. Demo (I used html-files, but I guess this will work with php-files as well):
test1.html:

<head>
<script type="text/javascript">
var pageRequest = false
/*@cc_on
@if (@_jscript_version >= 5)
try {
pageRequest = new ActiveXObject("Msxml2.XMLHTTP")
}
catch (e){
try {
pageRequest = new ActiveXObject("Microsoft.XMLHTTP")
}
catch (e2){
pageRequest = false
}
}
@end
@*/

if (!pageRequest && typeof XMLHttpRequest != 'undefined')
pageRequest = new XMLHttpRequest()

function include(content,id){
var newdiv = document.createElement("div");
newdiv.innerHTML = content;
document.getElementById(id).appendChild(newdiv);
}

if (pageRequest){
pageRequest.open('GET', 'test2.html', false)
pageRequest.send(null); ajax_include1=pageRequest.responseText;

document.write('<div style="display:none">');
document.write(ajax_include1);
document.write('<\/div>');
}
</script>
</head>

<body >

<div>
What you see above the horizontal line is content from <i>test1.html.</i><br><br>
Click on the link to add dynamic content (the date) from external <i>test2.html</i> to area below &rarr; <a href="javascript: void(0)" onclick=load_date()>what's the date?</a><br><br>
Click <a href="javascript: void(0)" onclick="document.getElementById('external').innerHTML=''; document.getElementById('external').style.background='white'">here</a> to empty the area below.
</div><hr>

<div id="external"></div>

</body>
test2.html:

<script type="text/javascript">
function load_date(){
var myDate = new Date();
document.getElementById('external').innerHTML+='Hello World! The date is: ' + myDate+'<br><br>';
document.getElementById('external').style.background='red';
document.getElementById('external').style.color='white';
}
</script>

If the imported external js is complicated, you should make it external with respect to the file to which it belongs (IE precaution).
===
Arie Molendijk.

Beagle72
07-04-2010, 06:13 PM
Your best bet might be combining PHP and javascript. PHP will execute as the server is fetching the content, javascript generally will not execute, but you can invoke javascript as part of your onreadystatechange function,


Unfortunately this won't work, as I am dynamically generating the javascript code in my actual project. That's why it's being fetched on a seperate page via AJAX. The javascript must be contained in file 2.

Think items being added and removed in real time from a list. Each item in the list has it's own DHTML menu, so the javascript needs to change/update with each refresh.


You can force scripts on AJAX imported pages to execute by document.writing the external pages containing the scripts into a hidden div.

I had thought about this, as some AJAX/COMET methods utilize hidden divs or hidden iframes.

I'm about ready to start working on this again today. I've got 3 good routes to try (jQuery, mootools, hidden div). I'll let you know how it turns out. Thanks for all your help.

molendijk
07-04-2010, 07:36 PM
I'm about ready to start working on this again today. I've got 3 good routes to try (jQuery, mootools, hidden div). I'll let you know how it turns out.
In the meantime I'll correct some errors in my previous post, which was written too hastily.
test1.html:

<head>
<script type="text/javascript">
var pageRequest = false
/*@cc_on
@if (@_jscript_version >= 5)
try {
pageRequest = new ActiveXObject("Msxml2.XMLHTTP")
}
catch (e){
try {
pageRequest = new ActiveXObject("Microsoft.XMLHTTP")
}
catch (e2){
pageRequest = false
}
}
@end
@*/

if (!pageRequest && typeof XMLHttpRequest != 'undefined')
pageRequest = new XMLHttpRequest()

function include(content,id){
var newdiv = document.createElement("div");
newdiv.innerHTML = content;
document.getElementById(id).appendChild(newdiv);
}

if (pageRequest){
pageRequest.open('GET', 'test2.html', false)
pageRequest.send(null); ajax_include=pageRequest.responseText;

document.write('<div style="display:none">');
document.write(ajax_include);
document.write('<\/div>');
}
</script>
</head>

<body >

<div>
What you see above the horizontal line is content from <i>test1.html.</i>. What you see below the horizontal line is content from <i>test2.html.</i> <br><br>
Click <a href="javascript: void(0)" onclick="document.getElementById('div1').innerHTML=''; document.getElementById('div1').style.background='white';document.getElementById('div2').innerHTML=''; document.getElementById('div2').style.background='white'">here</a> to empty the area below the horizontal line.<br><br>

<a href="javascript: void(0)" onclick="load_date()">Execute code from test2.html by directly referencing (in test1.html) a function (=load_date()) that is inside test2.html</a><br>

<a href="javascript: void(0)" onclick="include(ajax_include,'div1')">Import text and code from test2.html with the help of a function (=include(content,id)) that is inside test1.html</a>
</div><hr>

<div id="div1"></div><br>
<div id="div2"></div>

</body>
test2.html:

<head>
<script type="text/javascript">
function load_date(){
var myDate = new Date();
document.getElementById('div2').innerHTML+='Hello World! The date is: ' + myDate+'<br><br>';
document.getElementById('div2').style.background='red';
document.getElementById('div2').style.color='white';
}
</script>
</head>

<body>
<a href="javascript: void(0)" onclick="load_date()">This link is imported from test2.html. It loads the date using function load_date() (in test2.html)</a>
</body>
Arie.

Beagle72
07-04-2010, 08:46 PM
Arie,

Thanks a lot for your assistance. I managed to get it working thanks to your examples ;)

jscheuer1
07-06-2010, 12:42 PM
Arie,

That's not AJAX (Asynchronous JavaScript and XML), it's a synchronous request and can cause the page to hang.

Beagle72,

You say your external page is created dynamically, how?

Beagle72
07-06-2010, 06:43 PM
Well, in my application it's COMET.

You're sitting on a page with a COMET channel open. An event is triggered, and a message is sent on the COMET channel telling your browser to reload some data. That data is fetched from file 2 (with code similar to what I posted in my original example for file 1). A div on file 1 that contains the data is replaced (reloaded).

What I was having problems with, was when the data included javascript on page 2, that javascript wasn't triggering. I put together the above example to illustrate the issue.

My real file 2 is a list of usernames, each one of which spawns a dhtml window when clicked on. The dhtml windows weren't activating (the javascript was the problem).

But it's all working now.

molendijk
07-06-2010, 10:33 PM
That's not AJAX (Asynchronous JavaScript and XML), it's a synchronous request and can cause the page to hang.

My script is in fact a combination of http://www.dynamicdrive.com/dynamicindex17/ajaxincludes.htm (synchronous) and http://www.dynamicdrive.com/dynamicindex17/ajaxcontent.htm (asynchronous?).
If you remove the document.write lines in my script, it's similar to the second script above.
If there's a risk of a hanging page, I should do something about it. I've thoroughly tested the script, never had a page-hanging problem.
===
Arie.

jscheuer1
07-07-2010, 12:27 AM
never had a page-hanging problem.

Try it (synchronous request) when the requested file isn't there.

It will also hang if there is a problem with permissions, or if the server is experiencing high traffic, probably in other cases as well.

You are simply better off, if it's at all feasible, using an approach that doesn't have the drawbacks of both document.write() and the synchronous request.

molendijk
07-08-2010, 12:01 AM
Try it (synchronous request) when the requested file isn't there.
I tried it. I simply got a 'not-found' message. The page did not hang.


It will also hang if there is a problem with permissions, or if the server is experiencing high traffic, probably in other cases as well.
I put a very slowly loading image in test2.html. No problem either.

I did my testing with the following files:
test1.html:


<head>
<script type="text/javascript">
var pageRequest = false
/*@cc_on
@if (@_jscript_version >= 5)
try {
pageRequest = new ActiveXObject("Msxml2.XMLHTTP")
}
catch (e){
try {
pageRequest = new ActiveXObject("Microsoft.XMLHTTP")
}
catch (e2){
pageRequest = false
}
}
@end
@*/

if (!pageRequest && typeof XMLHttpRequest != 'undefined')
pageRequest = new XMLHttpRequest()

function include(content,id){
var newdiv = document.createElement("div");
newdiv.innerHTML = content;
document.getElementById(id).appendChild(newdiv);
}

if (pageRequest){
pageRequest.open('GET', 'test2.html', false)
pageRequest.send(null); ajax_include=pageRequest.responseText;

document.write('<div style="display:none">');
document.write(ajax_include);
document.write('<\/div>');
}
</script>

</head>

<body >

<div>
What you see above the horizontal line is content from <i>test1.html.</i>. What you see below the horizontal line is content from <i>test2.html.</i> <br><br>
Click <a href="javascript: void(0)" onclick="document.getElementById('div1').innerHTML=''; document.getElementById('div1').style.background='white';document.getElementById('div2').innerHTML=''; document.getElementById('div2').style.background='white';document.getElementById('div3').innerHTML=''">here</a> to empty the area below the horizontal line.<br><br>

<a href="javascript: void(0)" onclick="load_date();load_slow_image() ">Execute code from test2.html by directly referencing (in test1.html) 2 functions (=load_date() and load_slow_image()) that are inside test2.html</a><br>

<a href="javascript: void(0)" onclick="include(ajax_include,'div1');">Import text and code from test2.html with the help of a function (=include(content,id)) that is inside test1.html</a>
</div><hr>

<div id="div1"></div><br>
<div id="div2"></div><br>
<div id="div3"></div><br>

</body>
test2.html:

<head>
<script type="text/javascript">
function load_date(){
var myDate = new Date();
document.getElementById('div2').innerHTML+='Hello World! The date is: ' + myDate+'<br><br>';
document.getElementById('div2').style.background='red';
document.getElementById('div2').style.color='white';
}

function load_slow_image()
{
var src = "http://www.nasa.gov/images/content/84857main_EC04-0325-23_lg.jpg?" + Number(new Date);
document.getElementById('div3').innerHTML+="<img src=" + src + " height='240' width='300'>"
}
</script>
</head>

<body>
<a href="javascript: void(0)" onclick="load_date()">This link is imported from test2.html. It loads the date using function load_date() (in test2.html)</a><br>

<a href="javascript: void(0)" onclick="load_slow_image()">This link is imported from test2.html. It loads a slow image using function load_slow_image() (in test2.html)</a><br>

</body>
Arie.

jscheuer1
07-08-2010, 04:05 AM
Neither of those demonstrates a failed request or a heavy load. In the first case, the request succeeds, you just get something other than you were expecting. In the second case all you are doing is importing code to import the image. That code is small, it doesn't matter how large the image on NASA's server is. Your request for that is a normal HTTP request, just like if it were an img tag, in fact it is:



document.getElementById('div3').innerHTML+="<img src=" + src + " height='240' width='300'>"

None of this addresses the issue of document.write() to write out script code. That can have its own problems.

Best to use an external script tag. That's all you are doing anyway, you are just taking a long circuitous route that is more prone to error to do it.