Hack 61. Periodically Make a Remote Call


Make an HTTP request at a specified interval and update the web page with the response.

This hack updates a web page with new data every five seconds, without ever refreshing or rebuilding the page. The behavior is automatic and does not involve the user taking any action. The conventional way of initiating this behavior is to use a "client pull" page involving a Refresh response header set to a specified interval, but even this strategy involves requesting and rebuilding the entire page each time the refresh takes place.

See Chapter 18 of Bruce Perry's Java Servlet and JSP Cookbook (O'Reilly) for an example.


From the users' perspective, it may also be a little weird for the browser to suddenly "go on automatic" without them touching the keyboard, with the page going blank temporarily and the delays involved in the redisplaying of images and other embedded items. This hack updates only the content in a single div, with nothing else changing on the page and no page rebuild.

No Fooling Around

As this is a Ruby on Rails application, all of the handling of the request object and its return values is taken care of for the developer. Figure 7-13 shows what the application's view looks like in the Safari browser. The user requests the URL http://localhost:3000/hacks/interval. In a Rails application, this causes the calling of an action named interval, or a view template located at <web-app-root>/app/views/hacks/interval.rhtml.

Figure 7-13. Display new data periodically


This page monitors the Ajax request the same way as "Monitor Remote Calls with Rails" [Hack #56], but the displayed date is refreshed every five seconds in a very subtle manner. All this was accomplished by calling one built-in Rails method in the view, as well as four lines of server-side code. You don't have to fool around with initializing the request object and writing functions to handle its return values!

Here is the code for the view interval.rhtml, which shows the method the application uses, periodically_call_remote( ):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"         "http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head>     <meta http-equiv="content-type" content="text/html; charset=utf-8" />     <%= javascript_include_tag :defaults %>     <title>Periodic Ajax calls</title> </head> <body> <%= periodically_call_remote(:update => "complete",:frequency => 5,  :url => { :action => :increment }, :position => "top",  :success => "$('complete').innerHTML='';$('success').innerHTML='Success;  request status='+request.status",  :loading => "$('loading').innerHTML='Loading...'", :loaded => "$('loaded').innerHTML='Loaded; request status='+request.status",  :interactive => "$('inter').innerHTML=  'Interactive; request status='+request.status",  :failure => "$('failure').innerHTML='Failure; request status='+request.status") %> <h3>Periodically calling Ajax</h3> <div  style="font-size: 1.2em"></div> <div  style="font-size: 1.2em"></div> <div  style="font-size: 1.2em"></div> <div  style="font-size: 1.2em; color: green"></div> <div  style="font-size: 1.2em; color: red"></div> <div  style="font-size: 1.2em; color: green"></div> </body> </html>

The <%= javascript_include_tag :defaults %> part ensures that the view imports the script tags that the application requires to use the JavaScript-based Ajax mechanism (see "Make Your JavaScript Available to Rails Applications" [Hack #57]). You'll see these tags a little later.

Here are the first few parameters to periodically_call_remote( ):

periodically_call_remote(:update => "complete",:frequency => 5,  :url => { :action => :increment }

These parameters:

  • Specify the id of the HTML element (or div with id complete, in this case) that the request object will update.

  • Specify the frequency or interval in seconds for sending requests (five seconds).

  • Point to a Ruby on Rails action (increment) that will generate the response.

The entire parameter to periodically_call_remote( ) is a Ruby hash type, which is a lot like a JavaScript object literal. You can also call this method in the following manner:

<% _hash = {:update => "complete",:frequency => 5, :url => { :action => :increment },
:position => "top",
:success => "$('complete').innerHTML='';$('success').innerHTML='Success; request status='+request.status",
:loading => "$('loading').innerHTML='Loading...'",
:loaded => "$('loaded').innerHTML='Loaded; request status='+request.status",
:interactive => "$('inter').innerHTML='Interactive; request status='+request.status",
:failure => "$('failure').innerHTML='Failure; request status='+request.status"} %>

<%= periodically_call_remote(_hash) %>


Where's All the Action?

The increment action is the server-side component or code that provides the HTTP response to these periodic requests. In Rails, an action can be created as a Ruby method inside of the controller object. The method name is the name of the action. Our action, defined here, simply updates the current date:

class HacksController < ApplicationController       def increment         tz=TimeZone.create("TZ",-60*60*5)         render :text => tz.now(  ).to_s     end #rest of Controller code end

The increment( ) method creates a TimeZone object, which is included in the RoR API. This TimeZone is set for a five-hour negative offset from Greenwich mean time, which lines it up with Eastern standard time (EST). The object's now( ) method returns the current time in a formatted string, as Figure 7-13 shows. The code then uses RoR's render( ) method, which sends the date string as an HTTP response. The Ajax application calls this bit of code every five seconds, so the date string represents a date and time five seconds later than the previous one.

That's a lot of requests to hit the server with from one client! The requests will stop once another web page replaces this one in the browser, or the browser tab containing this page is closed. You can also provide a button or internal behavior to stop the periodical execution, as discussed in "Create Observers for Web Page Fields" [Hack #52].


Shrink-Wrapped

If you ventured through some of the earlier hacks in this chapter, you've probably already encountered the discussion about how these Ajax methods wrap objects that are made available by the Prototype package. Using ViewView Source from the Safari browser menu, you can see what the generated code for this page looks like. Here are the tags that import the JavaScript files:

<script src="/books/4/254/1/html/2//javascripts/prototype.js" type="text/javascript"></script> <script src="/books/4/254/1/html/2//javascripts/effects.js" type="text/javascript"></script> <script src="/books/4/254/1/html/2//javascripts/dragdrop.js" type="text/javascript"></script> <script src="/books/4/254/1/html/2//javascripts/controls.js" type="text/javascript"></script> <script src="/books/4/254/1/html/2//javascripts/application.js" type="text/javascript"></script>

Rails views are templates; the embedded method calls are replaced by the generated HTML code, which the web server sends back to the browser in response to a request for an RoR view.

Make sure that you import only the JavaScript files the page needs, because a separate GET request is required for each one.


The Rails application replaces the periodically_call_remote( ) code with the following:

<script type="text/javascript"> //<![CDATA[ new PeriodicalExecuter(function(  ) {new Ajax.Updater('complete',  '/hacks/increment', {asynchronous:true, evalScripts:true,  insertion:Insertion.Top,  onFailure:function(request){$('failure').innerHTML='Failure; request  status='+request.status},  onInteractive:function(request){$('inter').innerHTML='Interactive;  request status='+request.status},  onLoaded:function(request){$('loaded').innerHTML='Loaded; request  status='+request.status},  onLoading:function(request){$('loading').innerHTML='Loading...'},  onSuccess:function(request){$('complete').innerHTML='';$('success').innerHTML= 'Success; request status='+request.status}})}, 5) //]]> </script>

This is a script tag that encloses some JavaScript. The script creates a PeriodicalExecuter and an Ajax.Updater object from the Prototype package (see ). The PeriodicalExecuter takes as parameters to its constructor a callback function and the number of seconds to lapse before it executes again. The Ajax.Updater takes care of the Ajax- and request objectrelated work for us. Depending on how the developer likes to code, the Ajax magic is virtually shrink-wrapped!




Ajax Hacks
Ajax Hacks: Tips & Tools for Creating Responsive Web Sites
ISBN: 0596101694
EAN: 2147483647
Year: 2006
Pages: 138

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net