- •preface
- •acknowledgments
- •about this book
- •Who should read this book?
- •Roadmap
- •Code conventions
- •Code downloads
- •Author Online
- •About the title
- •About the cover illustration
- •Rethinking the web application
- •A new design for the Web
- •1.1 Why Ajax rich clients?
- •1.1.1 Comparing the user experiences
- •1.1.2 Network latency
- •1.1.3 Asynchronous interactions
- •1.1.4 Sovereign and transient usage patterns
- •1.1.5 Unlearning the Web
- •1.2 The four defining principles of Ajax
- •1.2.1 The browser hosts an application, not content
- •1.2.2 The server delivers data, not content
- •1.2.3 User interaction with the application can be fluid and continuous
- •1.2.4 This is real coding and requires discipline
- •1.3 Ajax rich clients in the real world
- •1.3.1 Surveying the field
- •1.3.2 Google Maps
- •1.4 Alternatives to Ajax
- •1.4.2 Java Web Start and related technologies
- •1.5 Summary
- •1.6 Resources
- •First steps with Ajax
- •2.1 The key elements of Ajax
- •2.2 Orchestrating the user experience with JavaScript
- •2.3 Defining look and feel using CSS
- •2.3.1 CSS selectors
- •2.3.2 CSS style properties
- •2.3.3 A simple CSS example
- •2.4 Organizing the view using the DOM
- •2.4.1 Working with the DOM using JavaScript
- •2.4.2 Finding a DOM node
- •2.4.3 Creating a DOM node
- •2.4.4 Adding styles to your document
- •2.4.5 A shortcut: Using the innerHTML property
- •2.5 Loading data asynchronously using XML technologies
- •2.5.1 IFrames
- •2.5.2 XmlDocument and XMLHttpRequest objects
- •2.5.3 Sending a request to the server
- •2.5.4 Using callback functions to monitor the request
- •2.5.5 The full lifecycle
- •2.6 What sets Ajax apart
- •2.7 Summary
- •2.8 Resources
- •Introducing order to Ajax
- •3.1 Order out of chaos
- •3.1.1 Patterns: creating a common vocabulary
- •3.1.2 Refactoring and Ajax
- •3.1.3 Keeping a sense of proportion
- •3.1.4 Refactoring in action
- •3.2 Some small refactoring case studies
- •3.2.2 Managing event handlers: Observer pattern
- •3.2.3 Reusing user action handlers: Command pattern
- •3.2.4 Keeping only one reference to a resource: Singleton pattern
- •3.3 Model-View-Controller
- •3.4 Web server MVC
- •3.4.1 The Ajax web server tier without patterns
- •3.4.2 Refactoring the domain model
- •3.4.3 Separating content from presentation
- •3.5 Third-party libraries and frameworks
- •3.5.2 Widgets and widget suites
- •3.5.3 Application frameworks
- •3.6 Summary
- •3.7 Resources
- •Core techniques
- •The page as an application
- •4.1 A different kind of MVC
- •4.1.1 Repeating the pattern at different scales
- •4.1.2 Applying MVC in the browser
- •4.2 The View in an Ajax application
- •4.2.1 Keeping the logic out of the View
- •4.2.2 Keeping the View out of the logic
- •4.3 The Controller in an Ajax application
- •4.3.1 Classic JavaScript event handlers
- •4.3.2 The W3C event model
- •4.3.3 Implementing a flexible event model in JavaScript
- •4.4 Models in an Ajax application
- •4.4.1 Using JavaScript to model the business domain
- •4.4.2 Interacting with the server
- •4.5 Generating the View from the Model
- •4.5.1 Reflecting on a JavaScript object
- •4.5.2 Dealing with arrays and objects
- •4.5.3 Adding a Controller
- •4.6 Summary
- •4.7 Resources
- •The role of the server
- •5.1 Working with the server side
- •5.2 Coding the server side
- •5.2.1 Popular implementation languages
- •5.3 The big picture: common server-side designs
- •5.3.1 Naive web server coding without a framework
- •5.3.2 Working with Model2 workflow frameworks
- •5.4 The details: exchanging data
- •5.4.2 Introducing the planet browser example
- •5.5 Writing to the server
- •5.5.1 Using HTML forms
- •5.5.2 Using the XMLHttpRequest object
- •5.5.3 Managing user updates effectively
- •5.6 Summary
- •5.7 Resources
- •Professional Ajax
- •The user experience
- •6.1 Getting it right: building a quality application
- •6.1.1 Responsiveness
- •6.1.2 Robustness
- •6.1.3 Consistency
- •6.1.4 Simplicity
- •6.1.5 Making it work
- •6.2 Keeping the user informed
- •6.2.1 Handling responses to our own requests
- •6.2.2 Handling updates from other users
- •6.3 Designing a notification system for Ajax
- •6.3.1 Modeling notifications
- •6.3.2 Defining user interface requirements
- •6.4 Implementing a notification framework
- •6.4.1 Rendering status bar icons
- •6.4.2 Rendering detailed notifications
- •6.4.3 Putting the pieces together
- •6.5 Using the framework with network requests
- •6.6 Indicating freshness of data
- •6.6.1 Defining a simple highlighting style
- •6.6.2 Highlighting with the Scriptaculous Effects library
- •6.7 Summary
- •6.8 Resources
- •Security and Ajax
- •7.1 JavaScript and browser security
- •7.1.1 Introducing the “server of origin” policy
- •7.1.2 Considerations for Ajax
- •7.1.3 Problems with subdomains
- •7.2 Communicating with remote services
- •7.2.1 Proxying remote services
- •7.2.2 Working with web services
- •7.3 Protecting confidential data
- •7.3.1 The man in the middle
- •7.3.2 Using secure HTTP
- •7.3.3 Encrypting data over plain HTTP using JavaScript
- •7.4 Policing access to Ajax data streams
- •7.4.1 Designing a secure web tier
- •7.4.2 Restricting access to web data
- •7.5 Summary
- •7.6 Resources
- •Performance
- •8.1 What is performance?
- •8.2 JavaScript execution speed
- •8.2.1 Timing your application the hard way
- •8.2.2 Using the Venkman profiler
- •8.2.3 Optimizing execution speed for Ajax
- •8.3 JavaScript memory footprint
- •8.3.1 Avoiding memory leaks
- •8.3.2 Special considerations for Ajax
- •8.4 Designing for performance
- •8.4.1 Measuring memory footprint
- •8.4.2 A simple example
- •8.5 Summary
- •8.6 Resources
- •Ajax by example
- •Dynamic double combo
- •9.1 A double-combo script
- •9.2 The client-side architecture
- •9.2.1 Designing the form
- •9.2.2 Designing the client/server interactions
- •9.3 Implementing the server: VB .NET
- •9.3.1 Defining the XML response format
- •9.4 Presenting the results
- •9.4.1 Navigating the XML document
- •9.4.2 Applying Cascading Style Sheets
- •9.5 Advanced issues
- •9.5.2 Moving from a double combo to a triple combo
- •9.6 Refactoring
- •9.6.1 New and improved net.ContentLoader
- •9.7 Summary
- •Type-ahead suggest
- •10.1 Examining type-ahead applications
- •10.1.2 Google Suggest
- •10.2.1 The server and the database
- •10.3 The client-side framework
- •10.3.1 The HTML
- •10.3.2 The JavaScript
- •10.3.3 Accessing the server
- •10.5 Refactoring
- •10.5.1 Day 1: developing the TextSuggest component game plan
- •10.5.3 Day 3: Ajax enabled
- •10.5.4 Day 4: handling events
- •10.5.6 Refactor debriefing
- •10.6 Summary
- •11.1 The evolving portal
- •11.1.1 The classic portal
- •11.1.2 The rich user interface portal
- •11.2 The Ajax portal architecture using Java
- •11.3 The Ajax login
- •11.3.1 The user table
- •11.4 Implementing DHTML windows
- •11.4.1 The portal windows database
- •11.4.3 Adding the JS external library
- •11.5 Adding Ajax autosave functionality
- •11.5.1 Adapting the library
- •11.5.2 Autosaving the information to the database
- •11.6 Refactoring
- •11.6.1 Defining the constructor
- •11.6.2 Adapting the AjaxWindows.js library
- •11.6.3 Specifying the portal commands
- •11.6.4 Performing the Ajax processing
- •11.6.5 Refactoring debrief
- •11.7 Summary
- •Live search using XSLT
- •12.1 Understanding the search techniques
- •12.1.1 Looking at the classic search
- •12.1.3 Examining a live search with Ajax and XSLT
- •12.1.4 Sending the results back to the client
- •12.2 The client-side code
- •12.2.1 Setting up the client
- •12.2.2 Initiating the process
- •12.3 The server-side code: PHP
- •12.3.1 Building the XML document
- •12.3.2 Building the XSLT document
- •12.4 Combining the XSLT and XML documents
- •12.4.1 Working with Microsoft Internet Explorer
- •12.4.2 Working with Mozilla
- •12.5 Completing the search
- •12.5.1 Applying a Cascading Style Sheet
- •12.5.2 Improving the search
- •12.5.3 Deciding to use XSLT
- •12.5.4 Overcoming the Ajax bookmark pitfall
- •12.6 Refactoring
- •12.6.1 An XSLTHelper
- •12.6.2 A live search component
- •12.6.3 Refactoring debriefing
- •12.7 Summary
- •Building stand-alone applications with Ajax
- •13.1 Reading information from the outside world
- •13.1.1 Discovering XML feeds
- •13.1.2 Examining the RSS structure
- •13.2 Creating the rich user interface
- •13.2.1 The process
- •13.2.3 Compliant CSS formatting
- •13.3 Loading the RSS feeds
- •13.3.1 Global scope
- •13.3.2 Ajax preloading functionality
- •13.4 Adding a rich transition effect
- •13.4.2 Implementing the fading transition
- •13.4.3 Integrating JavaScript timers
- •13.5 Additional functionality
- •13.5.1 Inserting additional feeds
- •13.5.2 Integrating the skipping and pausing functionality
- •13.6 Avoiding the project’s restrictions
- •13.6.1 Overcoming Mozilla’s security restriction
- •13.6.2 Changing the application scope
- •13.7 Refactoring
- •13.7.1 RSS reader Model
- •13.7.2 RSS reader view
- •13.7.3 RSS reader Controller
- •13.7.4 Refactoring debrief
- •13.8 Summary
- •The Ajax craftsperson’s toolkit
- •A.1 Working smarter with the right toolset
- •A.1.1 Acquiring tools that fit
- •A.1.2 Building your own tools
- •A.1.3 Maintaining your toolkit
- •A.2 Editors and IDEs
- •A.2.1 What to look for in a code editor
- •A.2.2 Current offerings
- •A.3 Debuggers
- •A.3.1 Why we use a debugger
- •A.3.2 JavaScript debuggers
- •A.3.3 HTTP debuggers
- •A.3.4 Building your own cross-browser output console
- •A.4 DOM inspectors
- •A.4.1 Using the Mozilla DOM Inspector
- •A.4.2 DOM inspectors for Internet Explorer
- •A.4.3 The Safari DOM Inspector for Mac OS X
- •A.5 Installing Firefox extensions
- •A.6 Resources
- •JavaScript for object-oriented programmers
- •B.1 JavaScript is not Java
- •B.2 Objects in JavaScript
- •B.2.1 Building ad hoc objects
- •B.2.2 Constructor functions, classes, and prototypes
- •B.2.3 Extending built-in classes
- •B.2.4 Inheritance of prototypes
- •B.2.5 Reflecting on JavaScript objects
- •B.2.6 Interfaces and duck typing
- •B.3 Methods and functions
- •B.3.1 Functions as first-class citizens
- •B.3.2 Attaching functions to objects
- •B.3.3 Borrowing functions from other objects
- •B.3.4 Ajax event handling and function contexts
- •B.3.5 Closures in JavaScript
- •B.4 Conclusions
- •B.5 Resources
- •Ajax frameworks and libraries
- •Accesskey Underlining Library
- •ActiveWidgets
- •Ajax JavaServer Faces Framework
- •Ajax JSP Tag Library
- •Ajax.NET
- •AjaxAC
- •AjaxAspects
- •AjaxCaller
- •AjaxFaces
- •BackBase
- •Behaviour
- •Bindows
- •BlueShoes
- •CakePHP
- •CL-Ajax
- •ComfortASP.NET
- •Coolest DHTML Calendar
- •Dojo
- •DWR (Direct Web Remoting)
- •Echo 2
- •FCKEditor
- •Flash JavaScript Integration Kit
- •Google AjaxSLT
- •Guise
- •HTMLHttpRequest
- •Interactive Website Framework
- •Jackbe
- •JPSpan
- •jsolait
- •JSON
- •JSRS (JavaScript Remote Scripting)
- •LibXMLHttpRequest
- •Mochikit
- •netWindows
- •Oddpost
- •OpenRico
- •Pragmatic Objects
- •Prototype
- •Qooxdoo
- •RSLite
- •Ruby on Rails
- •Sack
- •SAJAX
- •Sarissa
- •Scriptaculous
- •SWATO…
- •Tibet
- •TinyMCE
- •TrimPath Templates
- •Walter Zorn’s DHTML Libraries
- •WebORB for .NET
- •WebORB for Java
- •XAJAX
- •x-Desktop
- •XHConn
- •index
- •Symbols
- •Numerics
Understanding the search techniques |
467 |
|
|
With Ajax, it’s easy to perform server-side actions while controlling what is happening on the client. If a process takes an extended period of time, we can show animated GIFs that display messages that let the user know what’s happening. The user can perform other actions while the server-side process is taking place and will be less likely to think that the browser has frozen.
In this chapter, we use this Ajax technique to create a live search. It utilizes Extensible Stylesheet Language Transformations (XSLT) to transform an XML document into an HTML layout. The XSLT translation is easier to maintain than the code to manually parse the XML and produce HTML using JavaScript statements. It uses a tree-oriented transformation on a dynamically generated XML document, which replaces the server-side code and the JavaScript on which the previous projects relied. We are eliminating the hassles of manually making sure that all the HTML elements are formed properly.
As with previous examples, we first develop the code in a straightforward way and then refactor it into a reusable component. By the end of this chapter, you should understand the principles of using XSLT with Ajax and have a ready-rolled search component that you can drop into your own projects.
12.1 Understanding the search techniques
When we perform searches, we are accustomed to seeing the page freeze while the search is conducted on the server. (At least, this is the case on websites that do not have 1,200 clustered servers that perform a search over 8 billion pages in less than a second. The budget constraints of your project may vary.) To eliminate the pause, some developers implement pop-up windows and frames. The additional window is used to perform the processing so the user’s experience can be enhanced, but this also creates problems. With Ajax, we can eliminate the common delays of the classic form and frame submissions.
12.1.1Looking at the classic search
In a classic search process, when we include a search form on our website, one or more form elements are posted back to the server. Google’s main search page is an example. Google’s search page (www.google.com) contains a single textbox and two search buttons. Depending on what search action we select, the form either directs us to a list of records, which we can navigate, or takes us to a single result in that list. This design is well suited for a page that doesn’t have any other functionality, but if it is part of a larger project, the design may cause problems, such as losing the state of the page, clearing form fields, and so on. Figure 12.1 is
468CHAPTER 12
Live search using XSLT
Server
|
Process search |
|
|
and page |
|
|
generation |
|
Submit |
Render |
|
page |
page |
|
|
Display results |
Figure 12.1 |
Browser |
|
Classic search model showing the |
|
processing over a period of time |
a diagram of the classic search model, where the entire page is posted back to the server for processing and a complete, new results page is returned.
One source of delay is that database queries can take an extended period of time. The browser is not accessible to the user until the results are displayed, causing the page to seem as if it has become frozen or inaccessible. Developers attempt to alleviate this inaccessibility period by adding functionality to the page to notify the user that the process is happening. It’s important to note that this inaccessibility problem is not limited to search operations. It can appear when updating or deleting records in a database, running a complicated server-side transaction, and so on.
One way developers try to cope with this is to display an animated GIF, such as a status bar, while the server is processing the submission. A common question on forums such as JavaRanch (www.JavaRanch.com) is how this can be done. The problem with an animated GIF is that it does not always run. The GIF tends to remain on the first frame with Microsoft Internet Explorer and does not loop through the GIF animation cycle. Developers have reported that some users think that their browser has frozen since they do not see the animation, and they click the refresh button or close their browser.
The classic search form also suffers from the same problems as some of the previous examples in which the page has to be re-rendered. The scroll position of the page may be lost because the new page is loaded at the top of the page instead of where the action took place. The form fields may not stay filled in, which requires the user to enter the data again. Developers attempt to solve these problems by using frames and pop-up windows, but they end up creating more problems. Let’s take a look at the underlying reasons.
Understanding the search techniques |
469 |
|
|
12.1.2The flaws of the frame and pop-up methods
Developers have traditionally used frames, IFrames, and pop-up windows to avoid the problems with pages appearing to be frozen, losing scroll position, and so on. The frames and the pop-up window allow the processing to be continued in another part of the web page, so the user can manipulate the part of the form where the action originated. Not only can the user manipulate the form, but other JavaScript functions can be executed as well.
The frame and pop-up windows have other added benefits. The frame solution allows the returned record set to be scrolled while the search form elements remain in the view of the user. The pop-up window permits the result to be displayed in a separate window, taking the processing away from the main window. With some parent/child window communication, we can pass data from the child window back to the parent window to return results. The pop-up window is great for adding searches in large forms when the user needs specific information that can be hard to memorize. The window can also be set to close after the processing is complete. That is useful when we want to perform updates without returning any data.
Figure 12.2 shows how a search in a frame is implemented. The bottom frame is responsible for submitting the search request to the server, allowing the results to be processed. As a result of having the bottom frame initiate the search, the frame at the top of the window is still accessible to the user, unlike the classic search shown in figure 12.1.
Although these solutions solve the problems that we talked about earlier, they also introduce new problems. Frames have been (and still are) one of developers’ worst nightmares. The main problem is navigation, since we do not know how the frame will react with the browser. We wonder how the back button will affect the frame. Will the frame take us to the right page, will it destroy our
Server
Process search and frame generation
Submit |
Render |
frame |
frame |
Display results |
Figure 12.2
Process flow of a search
Browser |
executed in the frame model |
470CHAPTER 12
Live search using XSLT
frameset, or will it just not seem to work? These are the questions that are typically in our minds when testing. And what if the pages are opened in a browser that does not support framesets? To avoid this latter problem, we would have to include frame-detection scripts on the page, adding more weight to our application and introducing more code to manage, and thus increasing the complexity of our codebase.
Pop-up windows, on the other hand, are subject to pop-up blockers as users increasingly turn them on. Pop-up windows should have no problem if they are explicitly initiated by the user’s button click, but pop-up windows can be spawned by the browser automatically, such as an onload or onunload pop-up. These onload pop-up windows are often prevented from opening since they tend to be abused as advertisements. Some users block all pop-up windows—which means users will never get their results since no window will open.
Other problems can occur with pop-up windows, such as when the child window appears underneath its parent; the pop-up window cannot be seen since it is covered by the parent window. This is known as a pop-under. Another problem can happen when an action takes place in the parent window. If the user clicks a link or refreshes the page, the action can sever the child-parent relationship, resulting in loss of communication between the windows. When the page refreshes, the pop-up window object is destroyed; there is no way to carry the object from page to page in a reasonable manner.
As you can see, although the frame and pop-up methods solve the problems inherent in traditional form submission, their solutions may lead to bigger problems. One way to fix these problems is to use Ajax. Ajax handles server communication independently of the browser page, which allows our animations to play and maintains the page state; we do not have to worry about outside factors such as pop-up blockers and users closing the window because they think it is frozen.
12.1.3Examining a live search with Ajax and XSLT
We can improve the functionality of certain search features on a website by turning the search into a live search, which is how some developers are naming the functionality of Ajax searches. This search is performed without posting the entire page to the server (as in the traditional search), which means that the current state of the page can be maintained. In addition, we can run JavaScript and GIF animations without any major problems, since the results are displayed within the browser with innerHTML or other DOM methods.
Let’s say we have a search that triggers a long database transaction that appears to lock the page. With Ajax, the animation can start when the database
Understanding the search techniques |
471 |
|
|
transaction starts. When we begin to output the results, we can simply set the CSS display property of the animated image to none, which will make the animation disappear. A variation on this is to place the animation image in the output location where the results are to be displayed. When the transaction is complete, we replace the GIF with the results, so the wait image is removed. Either way, the user can still use the form while the XMLHttpRequest object is processing the data of the server.
Let’s look at a popular example of allowing the user to work with an application while processing is being done on the server: Google Maps. We send out a request to the server for, say, restaurants on Main Street, and we are still able to manipulate the map while the server processes our request. We do not have to wait as we would with a normal form submission. The server-side process then returns the results to the page, where they are displayed to the user. In the same way, our live search allows the user to interact with the page while the server is processing the data. Figure 12.3 shows Ajax’s process flow.
The Ajax approach to handling searches and long transitions allows us to eliminate the problems that we have faced with the other options used in the past. This live search feature is not only useful when used with a search engine like Google or Yahoo, but it can also be helpful for smaller lookups. For instance, we can use a live search to perform a lookup to a database table to retrieve information for some of the form fields, such as an address, based on what the user has entered so far—all while the user is filling in other fields. Any long transaction with the server can be turned into a live process, with the server providing incremental updates to the client, which are displayed in an unobtrusive way (see chapter 6). With Ajax, we can improve data transfer and get the results to the client in a richer environment.
Server
Process search and
generate data
XMLHttpRequest
Display results
Browser
Figure 12.3
Process flow of the Ajax model. The server-side process generates data, which the client-side code inserts into the page directly. Less bandwidth is used, and the user interface is smoother.