Reputation: 3286
What I have: - A database table called 'orders' that is constantly populated by some java module on the back-end. - A website running on Grails that displays those orders. More precisely - a list.gsp in the Orders view. - the list.gsp will display new orders if the refresh button is pressed on the browser.
What I need: - Some way for the .gsp page on a client to get refreshed automatically when a new order is placed on the database. - The autorefresh needs only to autorefresh the .gsp page when the client is already in the .gsp page. i.e. if a client is on the show.gsp for a particular order, then no need for autorefresh.
Things I though might help:
option1: Having a grails service that will periodically (every 5sec.) query the database to see if there are any new orders. If there are, then somehow from the .gsp page call again and re-render the .gsp page ??!
- suboption1-1: create and destroy a new connection every 5 sec.
- suboption1-2: create and keep a connection alive ... forever
================================================================================= Follow up:
How can I call a controller from java script?:
function checkDB()
{
t = setTimeout("com.mypackage.DBChecker.checkdbController.checkAction()", 5000)
}
================================================================================== Follow up 2:
So I almost got what I wanted working except that I can't figure out how to AJAX back to my list.gsp page only part of itself. I dont want to refresh the whole page, but only a division with id="refresh table". i.e. .
I have the following code at the moment that is not working:
<script type="text/javascript">
function checkDB()
{
var xmlhttp;
var xmlDoc;
var x;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
xmlDoc=xmlhttp.responseText;
x=xmlDoc.getElementsByTagId("refreshTable");
for (i=0;i<x.length;i++)
{
txt = x[i].childNodes[0].nodeValue;
}
document.getElementById("refreshTable").innerHTML=txt;
}
else
{
}
}
xmlhttp.open("GET","http://localhost:8080/Orderlord/checkdb/checkdb",true);
xmlhttp.send();
}
window.load = checkDB();
</script>
=================================================================
Follow up 3:
I succeed in returning only a partial page through my ajax call by copy/paste the div that i wanted to a separate gsp. I dont know how It is working - it's a bit of a magic to me, but everything works, except for when I try to sort the columns of my table. Then, only that partial gsp is rendered on my browser, without the rest of the initial page resulting, in a simple tabulated text page. Also once I end up in that kind of html page - the autorefresh doesnt work anymore, but as long as I will stay in the checkDB list view, the page will refresh every 5 seconds.
...So , how do I fix my problem
Another thing i cant figure out is how to return True/False from a controller to a javascript function in the gsp and how exactly did you have in mind for me to use it?
And lastly, I am currently using 'window.load = timeDB' inside my tag to call the timer function. I tried using , but for some reason I cant get it to work no matter what. Is there something I should keep in mind when using ?
Very lastly: What can I do to simply refresh part of the gsp every 5 sec?
Upvotes: 1
Views: 3666
Reputation: 3286
So the following piece of code in my list.gsp did it for me. I decided that just refreshing the 'div id="myDiv"' under question every 5sec it's good enough, otherwise I would have hit the server every 5 seconds anyway since I am querying the database.
<script type="text/javascript">
function ajaxrefresh()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
//alert("aaaaaaa")
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
else
{
//alert("state: "+xmlhttp.readyState)
//alert("status: "+xmlhttp.status)
}
}
xmlhttp.open("GET","http://${localHostAddress}:12080/Orderlord/refresh/refreshactiveorders",true);
xmlhttp.send();
var t=setTimeout(ajaxrefresh,5000);
}
window.load = ajaxrefresh();
</script>
Upvotes: 0
Reputation: 946
You could take the approach of setting a timer on the page via javascript. You would then invoke a lightweight ajax call from your gsp page back to your controller that would yield a true/false to indicate if you needed a full refresh. This is a fairly simple approach but you would want to be careful that the back end target of the ajax call is optimized as it will be called every 5 seconds for each user on that page. It also generates quite a bit of traffic.
I might explore the publish subscribe plugins from the earlier answer before falling back to this approach, however I have implemented the simple timer / ajax call (in the java struts world) on a medium size website with pretty good results.
Upvotes: 1
Reputation: 3532
What you're explaining is a typical publish - subscribe model.
There are a few plugins in grails that will help you do this. Look at Atmosphere and cometD for this. Both options provide this kind of pub/sub.
If they feel a little too heavy for what you want, you should checkout Pusher and the associated Grails plugin. It is a little nicer because you can just integrate a javascript library in your gsp page and do the push from the server side whenever an order is created. Feels slightly lighter than the 2 libraries above. It uses HTML5 web sockets.
Upvotes: 1