Ajax Hacks: Tips & Tools for Creating Responsive Web Sites
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.
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 ></div> <div ></div> <div ></div> <div ></div> <div ></div> <div ></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:
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.
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 View <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.
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! |
Категории