Vladdy 03-12-2003, 07:32 PM I posted this on another forum per request, but figure it may be beneficial to CF visitors as well:
Here are the basics on how to implement server polls using client-side javascript without reloading the HTML page.
Goal:
Get information from the server and use it to update HTML document without reloading it.
Solution:
Spread functionality between two files:
- HTML document page.html
- Server-side script dataserver.asp that provides the data.
For the sake of simplicity we are going to have a couple of links in HTML document, which when clicked will activate the script that polls the server. Returned information will be displayed in an alert box.
<html>
<head>
<title>Background Server Poll Demo</title>
<script>
function pollServer(query)
{ if(script) return false; //Do not send new request while
//there is one being processed
script = document.createElement('script');
script.src = ‘dataserver.asp?’ + query;
document.getElementsByTagName('head')[0].appendChild(script);
}
function processServerResponse(data)
{ alert(‘Server returned: ‘ + data);
setTimeout(‘requestProcessed()’,50);
return;
}
function requestProcessed()
{ document.getElementsByTagName('head')[0].removeChild(script);
script = null;
return;
}
</script>
</head>
<body>
<a href=”#” onclick=”pollServer(‘get=info1’); return false;”>Get info 1</a>
<a href=”#” onclick=”pollServer(‘get=info2’); return false;”>Get info 2</a>
</body>
</html>
Server side code:
<% ‘Add all the prerequisite code here
‘ We are returning js !!!
Response.Content = “text/javascript”
‘ Add all the happy http stuff to disable caching here
‘ like Response.Expires = Yesterday
Action = Request.QueryString(“get”)
If Action = “info1”Then
ReturnedData = “Returned info1 data”
Else If Action = “info2” Then
ReturnedData = “Returned info2 data”
‘Expand as needed
End If
%>
processServerResponse(‘<%=ReturnedData%>’);
<% ‘ That is pretty much it.
%>
How it works
When you click on one of the links the pollServer function is called. It creates a new script node and sets the node’s src attribute to the name of the server-side script file with attached query string that was passed as a function parameter. It then appends the created node to the document head. At this point the request is set to the server to get the javascript code to execute.
The server side script examines the query string and populates the ReturnedData string with requested information. This string is returned as a parameter to the processServerResponse function. As a result the client gets a javascript containing one line which is a call to a function residing with the HTML page.
The processServerResponse function displays the received data in alert box. Then it calls the requestProcessed function via setTimout (QUIZ: Why it is important to use setTimout and not the straight call?)
The requestProcessed function removes the script node from the document head.
Turning it into a practical application
As shown the new requests are ignored until the current one is being processed. Reception of requests from the user and their processing should be untied so that a queue can be formed.
Server side script can obtain data from sources such as files, databases and whatever else you desire. The resultant data string can be delimited to represent tables and such as long as the format is “agreed upon” between the server-side script delivering data and client side script that is presenting it.
It goes without saying that client side script can present the received data on the page and not in alert box.
peterinwa 03-14-2003, 04:22 PM I taught myself HTML and some JS (with much help from this forum), but doubt that I'm capable of teaching myself how to do anything on the server side. Sorry, I should have said that in my post.
By the way, it looks like you're conditionally loading one set of data or the other from the server via conditional coding on the server. That's just what I wanted to do but with conditional coding on the browser side.
I can of course put conditional coding in the .js file I load, but then all data sets would have to be in that .js file which would defeat my purpose of not bringing them all into memory.
Unless I'm hopelessly confused.
Vladdy 03-14-2003, 04:47 PM The initial condition is processed at the client side when the query string is composed. In the given example there is a single "pipe-line" to the server, so the server side script checks for the condition passed to it and returns data accordingly. You can have pure client side solution if your data is separated in the different files that you want to load conditionally.
In this case you can have a loadScript function (instead of pollServer) that would look like that:
function loadScript(file)
{script = document.createElement('script');
script.src = file;
document.getElementsByTagName('head')[0].appendChild(script);
}
Then you can have something like this in your code
if(browser=="IE") loadScript("IEScripts.js");
else loadScript("CompliantScripts.js");
peterinwa 03-14-2003, 04:52 PM I understand that, but doing anything on the server side is out of the question for me. Thanks for your posts... it helps to know I can't do what I want on the browser side. I'll stop thinking about it and sleep tonight! LOL
Vladdy 03-14-2003, 04:56 PM Sorry I did not understand your question at first. You can have the client-side only solution. See the editing of my response.
BTW, Peter, I went to your site and tried the calculator. I think there is something very wrong with it::D :D :D
Shaving (face or body)
181 calories in 1 hr
Sexual Activity - vigorous
136 calories in 1 hr
peterinwa 03-14-2003, 06:19 PM Wow, I posted about this a year or so ago (can't find the old thread) and got nowhere. I thought I'd try again. I'm thrilled that it can be done!
I don't understand all your code (and I like to understand everything I use so I'll get my books out) but it's so short and simple I'll try it when I have time later today. I hope you get e-mails or will check back to see if I have further questions. I'm very grateful.
About my website, my FAQs explain my data sources and yes, there are many discrepancies. But they're the best there is.
If I had a mask that read CO2 output I'd put it on and test the sex numbers myself. Perhaps the shaving is higher because the person is doing it very fast to get ready for sex, but they are very passive in bed.
This is already getting borderline for this forum, so I won't post the URL. But go to Google and you can find some really fun sites searching for something like "calories burned during sex."
To end on a business note... thanks again for the help! :thumbsup:
ConfusedOfLife 03-14-2003, 07:07 PM QUIZ: Why it is important to use setTimout and not the straight call?
My Answer:because when <script> is created, it calls processServerResponse( theServerInput ) and then it ends. If we wana simply write what the browser sees during the excecution of code, we can write something like this ( I persume that the function is populated with 3 ):
<script>
alert(‘Server returned: 3‘);
psuedo code: call requestProcessed() after 50 ms
</script>
So, if we put the closing script command in the same function without using setTimeout, our poor compiler faces something like this:
<script>
alert(‘Server returned: 3‘);
psuedo code: Commit Suicide! Close yourself!
</script>
So, we wana talk more scientific: A child can not close it's parent, or an object inside another object ( the parent object ) can not close its parent object. Am I right?!
ConfusedOfLife 03-14-2003, 07:20 PM Hi
Dear vladdy, your code is really cool, but I have a simple problem that really doesn't make me fully enjoy your code! I am trying to make a simple counter. I'm using PHP + MySQL for storing the number ( it's just a one cell table! ) but since it's not a server side thread, I don't post the php code. I'm using a button on my page that whenever you press it, it should make a <script> with a src pointing to a php file that reads the data from the table and outputs a normal alert(results) . So, it means whenever you press the button, the php file reads the current number, increments that by one and writes alert(resutls) to the <script>.
The problem is: With the first click it works, it means I can see my counter on the page, but when I push the button for the 2nd time, nothing happens. I'm sure that the removeScript() function ( the function that performs removeChild() ) isn't working. Well, I thought let's post the code and maybe Vladdy can help! So, may you please take a look at my code?! :o
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<script>
function activatePHPCounter()
{
if ( typeof(script) != "undefined" && script ) // The script is already in use
{
alert("Sorry, but you have to wait!");
return false;
}
script = document.createElement("script");
script.src = "counterScript.php";
document.getElementsByTagName("head")[0].appendChild(script);
return;
}
function write2Div( num )
{
document.getElementById("counter").innerHTML = num;
setTimeout('removeScript()', 50);
return;
}
function removeScript()
{
if ( typeof(script) != "undefined" )
{
document.getElementsByTagName("head")[0].removeChild(script);
script = null;
}
return;
}
</script>
</HEAD>
<BODY>
<blockquote>
Here I'm gonna make a kind of beautiful counter! Well, this is not going to be a normal counter, it'll be a server side counter that works
without refreshing the page! Cool, huh?
<br /><br />
<input type="button" value="Increment By One" onclick="activatePHPCounter();">
<br /><br />
<div id="counter" style="color: red"><div>
</blockquote>
</BODY>
</HTML>
peterinwa 03-14-2003, 07:25 PM Back to my problem, here is the code I am trying:
// Function to load a food list
function loadScript(file){
script=document.createElement('script');
script.src=file;
document.getElementsByTagName('head')[0].appendChild(script)}
V=1; // Of course this wouldn't be here but is set elsewhere
if(V==1){loadScript("list_food.js")}
else {loadScript("list_mcdonalds.js")}
The page is coming up but the <select> menu is null, not containing the JS code in "list_food.js"
I don't fully understand the first four lines I copied so I could easily have some bad coding. Hey, that's always easy for me!
peterinwa 03-14-2003, 07:37 PM Where does:
// Function to load a food list
function loadScript(file){
script=document.createElement('script');
script.src=file;
document.getElementsByTagName('head')[0].appendChild(script)}
put the JS code from the .js file? Do I need another line to access the code? Or is it just dropped into the page.
Presently, with:
<script src="list_food.js"></script>
the JS just falls into the page. The actual code creates a database named with the variable "data" so I just insert "data" into my page where I want the data to appear.
ConfusedOfLife 03-14-2003, 07:40 PM I really think that it's better that you post this in the js thread and you also bring the contents of that external file that you're using.
Anyways, by using document.creatElement() and then appending it to a place ( a div, your document body or whatever ) you are dynamically making an element. So, by writing those four lines, it's like you had this static script from the beginning:
<script src="file"></script>
So, you see that the file that you put in the src should only cotain valid js functions ( not even a <script> tag ) and by using a server side file we exactly do the same thing: provide js contents to be written inside the <script> tag. If you have problems with it, I think it should be something wrong with that external file that you're using.
peterinwa 03-14-2003, 07:46 PM This is the external file content:
// list_general_030313.js
o='<option value=';
l=o+'0>General Food List';
l+=o+'62.5,.2,.4,16.2,2.9>Apple, raw with skin - small (2.5"/6.4 cm dia)';
l+=o+'81.4,.3,.5,21,3.7>Apple, raw with skin - medium (2.75"/7 cm dia)';
and it works fine with:
<script src="list_food.js"></script>
I build my page with c+=... and in the <select> where I want the data I have c+=l;
I'm really confused about this thread. I started a new thread this morning and at some point the subject changed and my original post disappeared from the top of this list of posts. ???
Vladdy 03-14-2003, 08:12 PM Originally posted by ConfusedOfLife
Hi
The problem is: With the first click it works, it means I can see my counter on the page, but when I push the button for the 2nd time, nothing happens. I'm sure that the removeScript() function ( the function that performs removeChild() ) isn't working. Well, I thought let's post the code and maybe Vladdy can help! So, may you please take a look at my code?!
Add alert to your write2Div function and see if it is called every time you press the button. If it is, then the problem is that the return of your PHP script was cached and the request never reached the server (same value is returned). If not, I have to think about it. Also, add the following line to the script creation code before appending node to the head.(I omitted it for brevity, but never tested if it was important..)
script.type = 'text/javascript';
A+ on the quiz, BTW
Vladdy 03-14-2003, 08:16 PM Peter,
Put the conditional code that selects the file to load into a function and call using body onload. This will assure that document.head exisits.
peterinwa 03-14-2003, 08:22 PM Can you give me sample syntax? Takes me hours to figure stuff out from books. Thanks!
I put an alert in the loadScript function and it is getting called and script.src=file is getting set correctly for what that's worth.
Thanks for all the help... I've wanted to do this for YEARS!
peterinwa 03-14-2003, 09:08 PM This should help. My frames pages are so complex that I made a simple test page to get to the bottom of the problem. Note that I always get the alert message, so I know the loadScript function is being called.
The error message is 'x' is undefined.
Complete main page coding:
<!-- test.html -->
<html>
<head>
<script language="JavaScript">
// Function to load test .js file
function loadScript(file){
alert("in loadScript function");
script=document.createElement('script');
script.src=file;
document.getElementsByTagName('head')[0].appendChild(script)}
// Select .js file (This would normally be conditional.)
loadScript("testJSfile.js");
c="<body><center>";
// It works with the following line turned on:
// x="My test .js file.";
// Or with the following line turned on and the X's removed:
// </Xscript><Xscript src="testJSfile.js"></Xscript><Xscript language="JavaScript">
c+=x;
c+="</center></body></html>";
document.write(c);
</script>
Complete .js file coding:
// testJSfile.js
x="My test .js file.";
This oughta help! :o
ConfusedOfLife 03-15-2003, 08:21 PM Note that I always get the alert message, so I know the loadScript function is being called.
It's no need to put an alert for that I think, you call it yourself and it's always called of course! What we want to see is if the js file is appended or not. So, I recommend you put an alert inside the js file, like writting this inside testJSfile.js:
alert("Hello! I'm inside the testJSfile");
I also couldn't understand the Xs in your code, whehter they're in the js file or in the original html file and what is their use?
PS: I know that you are asking for testing this new technique ( exactly why I'm asking too! ), but if you don't wana use server side code, then it's no need to use this way. You could simply call all your js files, but in those js files you should only have your function defined; e.g. you shouldn't call a function, just define it. Then inside the main html page, you can call each function that you want by having your conditions. It's what we use and this way is just good for doing server side scripts that usually reload the page.
liorean 03-15-2003, 08:39 PM Oh my - it looks like somebody will have to write an article about how to dynamically load javascripts ;-)
ConfusedOfLife 03-17-2003, 11:21 PM I think I more need to know how to remove javascript dynamically! If you look at my script, you see that it only works for the first time, and I think it's only because I can't remove the javascript part correctly! So, please write an article to address my problem too! It's about some days that I'm waiting for a simple help! :D
liorean 03-18-2003, 08:18 AM Be patient - writing an article takes time, both in laying it out, deciding what to include, testing examples and writing the text itself. Not to talk about having a few people corr. read it before posting it.
For technical reasons, you can't remove scripts from a page - the browser doesn't remember what the script did, thus it can't restore the page to what it would have been like without the script there. You'll simply have to design your scripts in such a way that they work with only adding them to the page.
In fact, this is the reason mozilla chose to not allow changing the src attribute of scripts.
Vladdy 03-18-2003, 11:41 AM Originally posted by ConfusedOfLife
I think I more need to know how to remove javascript dynamically! If you look at my script, you see that it only works for the first time, and I think it's only because I can't remove the javascript part correctly! So, please write an article to address my problem too! It's about some days that I'm waiting for a simple help! :D
Can you post your php file and complete html file, I'm curious to analyze the problem...
ConfusedOfLife 03-18-2003, 11:04 PM Wow! thanx God! Finally Vladdy is here to help.
Ok, the code is very simple, I have 2 files: a html file ( called normalHTML.html ) and a php file that messes with the counter ( called counterScript.php )
Here it is the html file:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<script>
function activatePHPCounter()
{
if ( typeof(script) != "undefined" && script ) // The script is already in use
{
alert("Sorry, but you have to wait!");
return false;
}
script = document.createElement("script");
script.src = "counterScript.php";
document.getElementsByTagName("head")[0].appendChild(script);
return;
}
function write2Div( num )
{
document.getElementById("counter").innerHTML = num;
setTimeout('removeScript()', 50);
return;
}
function removeScript()
{
if ( typeof(script) != "undefined" )
{
document.getElementsByTagName("head")[0].removeChild(script);
script = null;
}
return;
}
</script>
</HEAD>
<BODY>
<blockquote>
Here I'm gonna make a kind of beautiful counter! Well, this is not going to be a normal counter, it'll be a server side counter that works
without refreshing the page! Cool, huh?
<br /><br />
<input type="button" value="Increment By One" onclick="activatePHPCounter();">
<br /><br />
<div id="counter" style="color: red"><div>
</blockquote>
</BODY>
</HTML>
When you run this file, you see a button, if you press it, it shows you the current counter number and also increments it by one and stores it in the counter file/database. Well, you know that it's the php file that's actually doing this, but by writing it in this way, I expected it work like a normal js counter, that whenever I press the button, a new script be created and it shows the new number and increments it by one and finally stores it.
Here it is the php file:
<?PHP
$fileName = "counter.txt";
# If you use "a+" or "a" in fopen, you can not fseek it
# backward! It puts the fp at the end of the file and
# you can not go back! Beware!!!
if ( file_exists( $fileName) )
$fp = fopen( $fileName, "r+");
else
$fp = fopen( $fileName, "w+");
flock( $fp, 2);
$currNum = ( $oNum = fgets($fp, 1024) ) ? ( $oNum ) : ( 0 );
$currNum++;
# You can use fseek($fp, 0); insetead of rewind in here!
rewind($fp);
fwrite( $fp, $currNum);
flock( $fp, 3);
fclose($fp);
echo "alert($currNum);";
echo "setTimeout('removeScript()', 50);";
?>
For the php file, when I saw that my counter isn't working, or better to say it just worked for the first time that I pressed the button and then it stopped to work, I thought that it might be something wrong with it, so, I rewrote it with a database ( not a simple file ) and it didn't work either!
So, here it is the 2nd php file:
<?PHP
$link = mysql_connect("", "root", "****") or die("Error " . mysql_errno() . " : " . mysql_error() );
mysql_select_db("test");
$query = "select * from counter";
$res = mysql_query($query);
if ( !mysql_num_rows($res) )
{
# When you make table 'counter' for the first time and you run this script,
# this part gets excecuted! Means just once in the whole life of this script!
mysql_query("insert into counter values(1)");
}
else
{
$number = mysql_result( $res, 0);
mysql_query("update counter set Number = " . ( $number + 1 ) );
print "write2Div($number)";
}
?>
I see no reason that it doesn't work and the only thing that comes to mind is that for the 2nd time that it wants to make a script dynamically, it can not do it.
Cheers
PS: Dear liorean, I can wait as long as it takes! I know what you mean, writing isn't that easy when it comes to an article. It's about a month that a fellow Iranian site is asking me to write some articles for them, but I even didn't write one line!
Vladdy 03-19-2003, 01:05 PM I'm too busy to actually test what you got but....
Let's start by declaring the script variable in your js code as global, so that removeScript function can actually remove it...
<script>
var script = null;
function //.... and so on
</script>
Often the obvious things are hardest to spot :D :o
Also (I'm not that familiar with PHP) you need to make sure that the content of your responce is set to "text/javascript" not the often default "text/html" (ASP way would be Response.Content = "text/javascript" ).
Another thing is making sure that server response is not being cached (if nothing else helps you can add a global callNumber variable to the js script and use it as a part of a query string (PHP script will ignore it, but it will assure the request is sent to server every time):
var callNumber = 0;
function activatePHPCounter()
{ if ( typeof(script) != "undefined" && script )
// The script is already in use
{ alert("Sorry, but you have to wait!");
return false;
}
callNumber++;
script = document.createElement("script");
script.src = "counterScript.php?CN=" + callNumber;
document.getElementsByTagName("head")[0].appendChild(script);
return;
}
ConfusedOfLife 03-19-2003, 10:00 PM Thank you Vladdy
To be honest I just checked it on my own personal web server at my desktop, I'll upload it and tell you what's going on ( I already did it, but it gave me some bizzare errors that I don't wana fix at this hour of the night! ).
Laters,
bijan
|
|