PDA

View Full Version : Javascript into Ajax context... Unusual problem, no eval() issues



wenijah
11-08-2007, 06:16 AM
Hi everyone!

First thank you for reading this post and yes, you probably already see that kind of topic title somewhere but the problem I've got today might be different than the 100 topics I've seen so far that did not resolve my problem...

Environment and problem: I have a page A with Ajax.js and a <div id="ajx">Content</div> that changes when clicking on a link. Another page, page B, gets loaded into page A and (tries) to load a javascript. When I click on the page A's link, the page B gets loaded but the javascript doesn't load.

What else? I tried several things to get it work (load the javascript with the XHR request, load the javascript from an <img src="" onload="javascript.js">, eval();, global.eval(); with var global = this; to force the script to start, I also tried the script from various topics I've seen...) but nothing worked. Well it did when I tried to load the js with the XHR request but it did not load properly and since I must load the js at the end of page B and not at the beginning so it doesn't work.

Here are my scripts samples:

Ajax.js

var loadedobjects=""
var rootdomain="http://"+window.location.hostname

function ajaxpage(url, containerid, tp, poststr){
var page_request = false
if (window.XMLHttpRequest) // if Mozilla, Safari etc
page_request = new XMLHttpRequest()
else if (window.ActiveXObject){ // if IE
try {
page_request = new ActiveXObject("Msxml2.XMLHTTP")
}
catch (e){
try{
page_request = new ActiveXObject("Microsoft.XMLHTTP")
}
catch (e){}
}
}
else
return false
document.getElementById(containerid).innerHTML='<img src="http://localhost/img/ld.gif">'
page_request.onreadystatechange=function(){
loadpage(page_request, containerid)

}

if (tp != 'POST'){
page_request.open('GET', url, true)
page_request.send(null)
} else {
page_request.open('POST', url, true);
page_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
page_request.setRequestHeader("Content-length", poststr.length);
page_request.setRequestHeader("Connection", "close");
page_request.send(poststr);
}
}

function loadpage(page_request, containerid){
if (page_request.readyState == 4 && (page_request.status==200 || window.location.href.indexOf("http")==-1))
document.getElementById(containerid).innerHTML=page_request.responseText
}

function loadobjs(){
if (!document.getElementById)
return
for (i=0; i<arguments.length; i++){
var file=arguments[i]
var fileref=""
if (loadedobjects.indexOf(file)==-1){ //Check to see if this object has not already been added to page before proceeding
if (file.indexOf(".js")!=-1){ //If object is a js file
fileref=document.createElement('script')
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src", file);
}
else if (file.indexOf(".css")!=-1){ //If object is a css file
fileref=document.createElement("link")
fileref.setAttribute("rel", "stylesheet");
fileref.setAttribute("type", "text/css");
fileref.setAttribute("href", file);
}
}
if (fileref!=""){
document.getElementsByTagName("head").item(0).appendChild(fileref)
loadedobjects+=file+" " //Remember this object as being already added to page
}
}
}


Page A ### loadobjs is the method that load the js with the XHR

<a href="#" onclick="javascript:ajaxpage('up/load', 'ajx', 'GET'); loadobjs(alpha.js)">Upload</a>
<br>
<div id="ajx"></div>

Page B

<script>
var ext_allowed='<TMPL_VAR ext_allowed>';
var ext_not_allowed='<TMPL_VAR ext_not_allowed>';
var max_files=<TMPL_VAR max_files>;
var max_size=<TMPL_VAR max_size>;
var descr_mode=<TMPL_VAR enable_file_descr>;
</script>

##> Page design and information <###

<iframe src="javascript:false;" name="alpha" style="position:absolute;left:-9999px;"></iframe>
<script>InitSelector();</script>

So, for the page B, I need to load the first script with has no function but providing information and the InitSelector(); which is inside alpha.js. This is an atypic request but there must be something to solve it, init?

Thanks a lot in advance.. I've been chasing a solution for 20hours... dang! :-[

uNo! Weni

Twey
11-08-2007, 06:42 AM
Nothing new here :p

The traditional solution is to loop through all the script elements in the element once it's been parsed and eval() their innerHTML. This kind of works, but it's ugly and in some cases will fail. Instead, I suggest that rather than sending the response as a big blob of HTML, you encode it in a format more readily accessible to Javascript, such as XML or JSON, and recreate it that way. E.G., instead of sending:
<script type="text/javascript" src="somescript.js"></script>
<p id="someID">
<span class="someClass">Some text...</span>
Some more text...
</p>You might send:
[
{"_tag" : "script",
"type" : "text/javascript",
"src" : "somescript.js"
},
{"_tag" : "p",
"id" : "someID",
"_children" : [
{"_tag" : "span",
"className" : "someClass",
"_children" : ["Some text..."]
},
"Some more text"
]
}
]Here's a sample JSON-to-DOM parser for this format:
function jsonToDom(o) {
if (typeof o === "string")
return document.createTextNode(o);

var r = document.createElement(o._tag);

for (var x in o)
if (o.hasOwnProperty(x)
&& x.indexOf("_") !== 0)
r[x] = o[x];

if(o._children && o._children.length)
for (var i = 0, e = o._children, n = e.length; i < n; ++i)
r.appendChild(jsonToDom(e[i]));

return r;
}

wenijah
11-08-2007, 06:51 AM
Thanks a lot for your reply Twey!! May I ask you something else though? I'm not sure I get it all and I don't know JSON thaaat much (matter of fact, I don't know it at all)... Where should I put...


[
{_tag: "script",
type: "text/javascript",
src: "somescript.js"
},
{_tag: "p",
id: "someID",
_children: [
{_tag: "span",
className: "someClass",
_children: ["Some text..."]
},
"Some more text"
],
}
]

...In the Ajax.js? As a function? And then use the JSON-to-DOM parser? Thanks for your help!

Twey
11-08-2007, 07:26 AM
I don't know JSON thaaat muchThere's nothing to know. JSON stands for JavaScript Object Notation. It just uses the standard Javascript object literal notation (well, a subset of it). If you know Javascript, you know JSON.

As for where to use it, the code I gave you above would be what you'd return from your server-side script rather than HTML. The Javascript would eval() that, then pass the resulting objects to the jsonToDom() function I provided above in order to obtain the equivalent DOM nodes. As a side effect of creating those nodes, however, everything necessary (e.g. scripts) would be pulled in and executed.

wenijah
11-08-2007, 07:37 AM
I see... Matter of fact, that's THE problem because I just cannot load the js before the page B is completly loaded... Otherwise it would already work..

Is it possible to load a javascript at the end of page B? If not, then I should reconsider my structure right now =/

Thank you!

(by the way, why does it say yingguo as your country?)

Twey
11-08-2007, 07:54 AM
I see... Matter of fact, that's THE problem because I just cannot load the js before the page B is completly loaded... Otherwise it would already work..You don't see :) The JSON objects I provided were a sample page B in themselves.


(by the way, why does it say yingguo as your country?)Yīng guó in Mandarin, えいこく (eikoku) in Japanese. England is the meaning in both, I think? I don't know much Mandarin.

wenijah
11-08-2007, 08:10 AM
Chea! Got it! =) Thank you and thanks w3school and HTML DOM Tutos.. Ok, so to be clear:

Page B will be a JS by itself? Like, I dont use HTML vars but only Nodes, right?

And everything will be parsed by the JsonToDOM function?

I'm not sure... page B is a "template" generated from a perl application... Will it be possible to retrieve all datas sent by the CGI into the new JS?

Thanks!!

(yeah yingguo is England in Mandarin.. Owee i'm learning mandarin, that's why lol)

Twey
11-08-2007, 11:07 AM
I'm not sure... page B is a "template" generated from a perl application... Will it be possible to retrieve all datas sent by the CGI into the new JS?Your server-side script can work exactly as it did before. Only the output format need change.
(yeah yingguo is England in Mandarin.. Owee i'm learning mandarin, that's why lol)It's a nice language. I wish I had time to study it in more depth (as I wish of so many things these days, it seems).

wenijah
11-08-2007, 02:03 PM
Mandarin is cool but i wish I could speak javascript better than mandarin ! :/ Well, I want to use the JSON-to-DOM parser but I just don't really know how integrate all that in my script... Like, does JSON-to-DOM has to be on page B or when I call AJAX? And what are the "[" and "]" before and after the vars to fetch the js? I'm sorry, I'm kinda lost there... I've found an issue but I hate using iframe so if you got a couple more minutes, could you just explain me how to set it up?

Thanks a lot!

~w~

Twey
11-08-2007, 06:01 PM
Well, I want to use the JSON-to-DOM parser but I just don't really know how integrate all that in my script... Like, does JSON-to-DOM has to be on page B or when I call AJAX?It has to be on page A. You use XMLHttpRequest (this isn't AJAX, there's no XML involved) to retrieve the content from your server-side script, evaluate it, then call jsonToDom() on the resulting object, before appending it to the <div>, or perhaps we should replace the <div> entirely.
And what are the "[" and "]" before and after the vars to fetch the js?Square brackets in Javascript indicate an array. If we were to replace the <div>, however, that wouldn't be necessary.
// xhr.js

var XHR = {
jsonToDom: function jsonToDom(o) {
if (typeof o === "string")
return document.createTextNode(o);

var r = document.createElement(o._tag);

for (var x in o)
if (o.hasOwnProperty(x)
&& x.indexOf("_") !== 0)
r[x] = o[x];

if(o._children && o._children.length)
for (var i = 0, e = o._children, n = e.length; i < n; ++i)
r.appendChild(jsonToDom(e[i]));

return r;
},
getXHR: function() {
if(typeof XMLHttpRequest === "function")
return new XMLHttpRequest();
else if(ActiveXObject)
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
return null;
}
}
else return null;
},
updateElement: function(url, element) {
var xhr = XHR.getXHR();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if(this.readyState === 4 && this.status === 200) {
element.parentNode.replaceChild(jsonToDom(eval("(" + xhr.responseText + ")")), element);
xhr = element = null;
}
};
xhr.send(null);
}
};
<!-- Page A -->
<style type="text/css">
iframe.alpha-frame {
position: absolute;
left: -9999%;
}
</style>
<script type="text/javascript" src="xhr.js"></script>
<script type="text/javascript" src="alpha.js"></script>
</head>
<body>
<p>
<!-- Your previous use of <br> was an abuse. -->
<a
href="up/load"
onclick="XHR.updateElement(this.href + '?xhr=true', document.getElementById('ajx')); return false;">
Upload
</a>
<div id="ajx"></div>Note: up/load should return a full HTML page if accessed directly (without the GET "xhr" parameter) for non-Javascript users.
##> Page B <###
{"_tag" : "div",
"id" : "ajx",
"_children" : [
{"_tag" : "script",
"type" : "text/javascript",
"_children" : [
"var ext_allowed = '<TMPL_VAR ext_allowed>';",
"var ext_not_allowed = '<TMPL_VAR ext_not_allowed>';",
"var max_files = <TMPL_VAR max_files>;",
"var max_size = <TMPL_VAR max_size>;",
"var descr_mode = <TMPL_VAR enable_file_descr>;"]},

{"_tag" : "iframe",
"src" : "about:blank",
"name" : "alpha",
"className" : "alpha-frame"},

{"_tag" : "script",
"type" : "text/javascript",
"_children" : ["InitSelector();"]}]}

wenijah
11-09-2007, 12:42 AM
Ok, I tried with that and I think the Json-To-DOM parser doesn't work cause when pageA calls pageB.html it returns exactly the code as it's been posted and nothing show up..

{"_tag" : "div",
"id" : "ajx",
"_children" : [
{"_tag" : "script...

[...]
....ascript",
"_children" : ["InitSelector();"]}]}

Also, since I have to load alpha.js in page A then I got problem, I get an error "f has no properties
getFormAction(undefined)alpha.js (line 254)
[Break on this error] for(i=0;i<=f.attributes.length;i++)' but I guess I can fix that =)

Thanks a lot Twey!

Twey
11-09-2007, 01:57 AM
May I see the page?

wenijah
11-09-2007, 06:06 AM
Yep, there we go:

Test.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<style type="text/css">
iframe.alpha-frame {
position: absolute;
left: -9999%;
}
</style>
<script type="text/javascript" src="xhr.js"></script>
<script type="text/javascript" src="alpha.js"></script>
</head>
<body>
<p>
<a
href="upload"
onclick="XHR.updateElement(this.href + '?xhr=true', document.getElementById('ajx')); return false;">
Upload
</a>
<div id="ajx"></div>

</body>
</html>


xhr.js

// xhr.js

var XHR = {
jsonToDom: function jsonToDom(o) {
if (typeof o === "string")
return document.createTextNode(o);

var r = document.createElement(o._tag);

for (var x in o)
if (o.hasOwnProperty(x)
&& x.indexOf("_") !== 0)
r[x] = o[x];

if(o._children && o._children.length)
for (var i = 0, e = o._children, n = e.length; i < n; ++i)
r.appendChild(jsonToDom(e[i]));

return r;
},
getXHR: function() {
if(typeof XMLHttpRequest === "function")
return new XMLHttpRequest();
else if(ActiveXObject)
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
return null;
}
}
else return null;
},
updateElement: function(url, element) {
var xhr = XHR.getXHR();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if(this.readyState === 4 && this.status === 200) {
element.parentNode.replaceChild(jsonToDom(eval("(" + xhr.responseText + ")")), element);
xhr = element = null;
}
};
xhr.send(null);
}
}


PAGE B.html

{"_tag" : "div",
"id" : "ajx",
"_children" : [
{"_tag" : "script",
"type" : "text/javascript",
"_children" : [
"var ext_allowed = '<TMPL_VAR ext_allowed>';",
"var ext_not_allowed = '<TMPL_VAR ext_not_allowed>';",
"var max_files = <TMPL_VAR max_files>;",
"var max_size = <TMPL_VAR max_size>;",
"var descr_mode = <TMPL_VAR enable_file_descr>;"]},

{"_tag" : "p",
"_children" : [
"ok"]},

{"_tag" : "iframe",
"src" : "about:blank",
"name" : "alpha",
"className" : "alpha-frame"},

{"_tag" : "script",
"type" : "text/javascript",
"_children" : ["InitSelector();"]}]}

=/ Well, it's a copy & paste from your post, except for the <p>

Thanks again!

EDIT: Oweee I better have to get it to work... the iframe doesn't work under Opera... crud..

Twey
11-09-2007, 01:25 PM
Ah! For a start it should be XHR.jsonToDom():
var XHR = {
jsonToDom: function(o) {
if (typeof o === "string")
return document.createTextNode(o);

var r = document.createElement(o._tag);

for (var x in o)
if (o.hasOwnProperty(x)
&& x.indexOf("_") !== 0)
r[x] = o[x];

if(o._children && o._children.length)
for (var i = 0, e = o._children, n = e.length; i < n; ++i)
r.appendChild(XHR.jsonToDom(e[i]));

return r;
},
getXHR: function() {
if(typeof XMLHttpRequest === "function")
return new XMLHttpRequest();
else if(ActiveXObject)
try {
return new ActiveXObject("Msxml2.XMLHTTP");
} catch (e1) {
try {
return new ActiveXObject("Microsoft.XMLHTTP");
} catch (e2) {
return null;
}
}
else return null;
},
updateElement: function(url, element) {
var xhr = XHR.getXHR();
xhr.open("GET", url, true);
xhr.onreadystatechange = function() {
if(this.readyState === 4 && this.status === 200) {
element.parentNode.replaceChild(XHR.jsonToDom(eval("(" + xhr.responseText + ")")), element);
xhr = element = null;
}
};
xhr.send(null);
}
}You should've got an error from this. If it doesn't work this time around, please post the error(s) you get in your error console (preferably Firefox').

wenijah
11-09-2007, 02:17 PM
Dang... I really don't get why it's so difficult to load a js.. I tried again but it's still blank but Firebug doesn't mention any error! Does it mean the js works though?

Thank you very much for your help! N sorry to annoy you with this =/