Martin Klosi
Martin Klosi

Reputation: 3286

Autorefresh a .gsp in Grails when a database table changes

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:

================================================================================= 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.

  1. ...So , how do I fix my problem

  2. 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?

  3. 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

Answers (3)

Martin Klosi
Martin Klosi

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

Bill Pfeiffer
Bill Pfeiffer

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

Tomas Lin
Tomas Lin

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

Related Questions