Simple Ajax app (update html page, no refreshing/no flicker)

Post your example source code and application notes to share with others
User avatar
Forrest
Posts: 283
Joined: Wed Apr 23, 2008 10:05 am

Simple Ajax app (update html page, no refreshing/no flicker)

Post by Forrest »

Hey all, I just wrote this real simple application as a demo for you all. This was designed to run on any of our network enabled modules.

Credit to Todd Gentille at Syncor Systems for the original idea and base. You can find his original example at http://www.netburner.com/support/techni ... ments.html.

This application is simply a webpage that counts up the Ticks that the netburner module has been running. It displays the ticks on the webpage counting up without having to refresh the webpage. This is accomplished by using Ajax in Javascript to query another webpage that calls a NetBurner HTML function to get the Ticks from the board. This other webpage is queried every 5 millisecs. To the code:


main.cpp - Nothing special here, only the web function call:

Code: Select all

void getHTMLTicks(int sock, PCSTR url) {
	char tick[40];
	siprintf(tick, "%d", TimeTick);
	writestring(sock, tick);
}
ticks.html - just calls the getHTMLTicks function. This page is what javascript is refreshing and getting results to inject

Code: Select all

<!--FUNCTIONCALL getHTMLTicks -->
index.html - nearly all the code is running here:

Code: Select all

window.onload=function(){
	setInterval("processPage()", 20)
}
This is telling Javascript to run the function processPage every 20 ms

Code: Select all

function processPage() {
	url = 'ticks.html';
	// Most browser support
	if (window.XMLHttpRequest) req = new XMLHttpRequest();
	// IE5, IE6 support 
	else if (window.ActiveXObject) req = new ActiveXObject("Microsoft.XMLHTTP");
	if (req != null) {
		req.onreadystatechange = getTicks;		
		req.open("GET", url, true);
		req.send(null);
	}
	else {
		alert("Browser not supported");
	}
}
Function processPage has 2 purposes. First is to run a function in both non-ie and ie browsers. IE side seems to be buggy. Second function is to send an HTML get request for the ticks.html file. After the get request is sent, the function getTicks is called

Code: Select all

function getTicks() {
	if (req.readyState == 4) { // Complete
		if (req.status == 200) { // OK response
			document.getElementById("TICK").innerHTML = req.responseText;
		}
	}
}
getTicks waits for the HTML get request from the processPage function to come back. If the request is successful, it injects the results into the TICK span in the main html code

Code: Select all

<HTML>
<BODY>
The NetBurner has been up for <span id="TICK"></span> ticks.
</BODY>
</HTML>
This creates the webpage and adds a TICK span. The injected results will go into the span section.

Thats it. You can easily modify this source to add seamless updates to your own webpages running off the NetBurner board. Full example is attached to this message


Note: This application does not appear to run correctly in IE8. I have not tested other IE versions. If anyone knows why, id be happy to hear it. To me, it appears IE is caching my function page.
Attachments
SimpleAjaxHTML.zip
(1.38 KiB) Downloaded 1112 times
Forrest Stanley
Project Engineer
NetBurner, Inc

NetBurner Learn Articles: http://www.netburner.com/learn
rsg
Posts: 54
Joined: Thu May 15, 2008 5:36 am

Re: Simple Ajax app (update html page, no refreshing/no flicker)

Post by rsg »

In this code:

Code: Select all

void getHTMLTicks(int sock, PCSTR url) {
   static char * tick = "";
   siprintf(tick, "%d", TimeTick);
   writestring(sock, tick);
}
How is it that these lines are not an error?

Code: Select all

   static char * tick = "";
   siprintf(tick, "%d", TimeTick);
Doesn't the siprintf overflow the buffer tick?
User avatar
Forrest
Posts: 283
Joined: Wed Apr 23, 2008 10:05 am

Re: Simple Ajax app (update html page, no refreshing/no flicker)

Post by Forrest »

You're right, you caught me copy and pasting some code from another app :o . Fixing it:

char tick[40];
siprintf(tick, "%d", TimeTick);
writestring(sock, tick);




rsg wrote:In this code:

Code: Select all

void getHTMLTicks(int sock, PCSTR url) {
   static char * tick = "";
   siprintf(tick, "%d", TimeTick);
   writestring(sock, tick);
}
How is it that these lines are not an error?

Code: Select all

   static char * tick = "";
   siprintf(tick, "%d", TimeTick);
Doesn't the siprintf overflow the buffer tick?
Forrest Stanley
Project Engineer
NetBurner, Inc

NetBurner Learn Articles: http://www.netburner.com/learn
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: Simple Ajax app (update html page, no refreshing/no flicker)

Post by rnixon »

I think he must know that there is nothing important in memory after the address of tick ;)
Renewegy
Posts: 1
Joined: Wed Feb 24, 2010 8:01 am

Re: Simple Ajax app (update html page, no refreshing/no flicker)

Post by Renewegy »

Thx for the post, it was very helpful!

I did some messing around and figured out how to get it to work with IE8, you were correct, IE was caching the ticks.html page and not updating.

This seems like a hack, but I found numerous websites that recommended using this.

I changed the line:

url = 'ticks.html';
to
url = 'ticks.html'+'?'+Math.random()*Math.random();

This forces IE to load the page because of the random number and keep loading.

Gotta love IE!
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: Simple Ajax app (update html page, no refreshing/no flicker)

Post by tod »

In reference to
I did some messing around and figured out how to get it to work with IE8, you were correct, IE was caching the ticks.html page and not updating.
The preferred way (IMO) to get around aggressive caching is as follows (where req is the XMLHttpRequest object created in the orginal post).

Code: Select all

req.SetRequestHeader('If-Modified-Since','Sat, 1 Jan 2000 00:00:00 GMT');
I actually use the Prototype library and with that you can add a property when creating the request like so:

Code: Select all

new Ajax.Request (callbackPage,{....normal parameters in any order then...
 requestHeaders:["If-Modified-Since","Sat, 1 Jan 2000 00:00:00 GMT"],
... other parameters
})
I think it's a good learning curve to do all this AJAX code by hand once, but once you've learned it I would suggest switching over to a library like Prototype instead. It takes care of all the browser differences for you.
A few weeks back I updated all my AJAX samples to be more of a production-ready library. I included all my custom library code (it's here in the forum) so if you just include the proper js files you can do AJAX calls without all the mess. In the post the ProcessPage() function would get replaced by

Code: Select all

	
syn.MakeAjaxRequest('ticks.html',getTicks);
This makes it much easier to add multiple Ajax calls. I didn't update the white paper but I did post a blog entry http://syncor.blogspot.com/2009/12/ajax ... und-2.htmland make a ten minute screencast explaining the basics of using the new code.
aahelee
Posts: 1
Joined: Tue Jun 28, 2011 11:16 pm

Re: Simple Ajax app (update html page, no refreshing/no flic

Post by aahelee »

How can I make a javascript button display an image instead? I am trying to write a javascript code that takes you to another random page on the site. That part works well, but I don't want it to be accessed by a button. Instead I want it to be when they click on an image it takes them to a random page. I know making a link for an image in html is easy but I'm not very proficient in javascript. Any help?
xAPPO
Posts: 6
Joined: Fri Jun 10, 2011 7:39 am

Re: Simple Ajax app (update html page, no refreshing/no flic

Post by xAPPO »

I'm reworking some old Ajax code I had in a previous application inline with this library - thanks Tom :-)

My application has a 16x16 status grid of icons that change colour within a table so quite a lot of elements. I noticed that quite a lot of network traffic and associated processing time is apparent, even in the original sample application. So I had some thoughts, which are always dangerous with my little knowledge. Please let me know if they are viable.

My first very general realisation was that within HtmlServices::WriteSampleJsonData() you should only return values that have actually updated via the JSON object, omitting any that remained the same. This minimises the work the JavaScript ID matching code has to do and avoids unnecessary same value updates helping the browser's update speed . In the example code of course these were changing every time. You'll need to iterate through the JSON object (currently handled in shell.CreateSampleData) and use the name of each parameter to decide what to update as the object will now be of varying length/content.

Then , if no data had changed I thought about delaying the response from HtmlServices::WriteSampleJsonData () until something had updated. Investigation showed that you can delay this response by a considerable time (10's of seconds) without any apparent problem. I haven't established yet how long and if it varies browser by browser. After a defined time even if nothing has changed I chose to return an empty JSON object as a 'keep alive' anyway.

This has an impact on shell.StartClock , the existing timer function in SupportScripts.js that is used to kick off requests from the JS code. It continues sending Ajax requests even though it's not receiving replies so I initially altered the code such that a flag is set every time you receive the JSON response and this is tested before sending another request (and clearing the flag). If no response has been received it just waits until the next timer iteration. Seems to work as expected and network traffic was nicely reduced.

Lastly I decided the timer wasn't really now operating as a timer anymore and you could just kick off a new Ajax request immediately you get the last response and await a new reply, which arrives only when there is updated data or the keep alive timeout. This seems ideal as it provides near realtime Ajax response time with reduced processing and network overhead. It's really fast when it goes full belt.

The pacing of the Ajax interaction is now handled in two places effectively, the delay that NetBurner inserts before returning a response and the delay the JS code inserts before kicking off another request. You can have code in either place to slow the process down if you have a lot of rapidly updating information. In such a scenario you would want to group multiple updates into one JSON object response as well.

There are a few potential issues I likely need to consider to avoid a lockup. Returning the 'keep alive' response from NetBurner after a timeout even if nothing has changed hopefully assists this - and some timer operation that would still kick off an Ajax request from the JS code after a timeout, if it had not seen a response from the NetBurner to a previous one. [EDIT] - Actually I think TCP takes care of this for me , assuming there isn't actually a socket disconnect..

Any thoughts.. comments, ahhh but's... ?

Kevin

PS I see Prototype v1.7 is now released and a few comments about issues moving from 1.6 ... I haven't ventured that far yet.
xAPPO
Posts: 6
Joined: Fri Jun 10, 2011 7:39 am

Re: Simple Ajax app (update html page, no refreshing/no flic

Post by xAPPO »

Tod - when I try and run your original application under the debugger - even with no breakpoints set it fails at the page load - locking up immediately after

WriteSystemVarsToJavaScript() has been called
var _machineState=
{
debugState: 1,
checkBoxState: false
};

I'm fairly new to NetBurner any ideas why and how to avoid it ?

Kevin
User avatar
tod
Posts: 587
Joined: Sat Apr 26, 2008 8:27 am
Location: Southern California
Contact:

Re: Simple Ajax app (update html page, no refreshing/no flic

Post by tod »

Sorry I've been off in C# land for a while and you're probably more familiar with this version of the Ajax shell than I am at this point. I don't know why running a debug version would cause a problem.

Tod
Post Reply