Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Ajax JSF

Download as pdf or txt
Download as pdf or txt
You are on page 1of 7

bpcatalog: bpcatalog: Using JSF with AJAX Page 1 of 7

Using JavaServer Faces Technology with AJAX

Greg Murray, Tor Norbye, Ed Burns


Status: In Early Access
Problem Description
The Java 2 Enterprise Edition includes JavaServer Faces technology, which provides a mature and extensible user interface component model. The design of
this model makes it easy for application developers to create custom components by extending the standard components included with JavaServer Faces
technology and to reuse these components across applications.
The example featured in this entry includes a JavaServer Faces text field component that takes the name of a city. When the user begins entering characters in
the field, the application uses AJAX to perform auto completion on the data by matching the user's input to a list of cities stored on the server. In two of the
versions of this example, the text field component is a custom JavaServer Faces component that provides the AJAX support. This component shields the page
author from the complexities of AJAX by rendering all the HTML and JavaScript code that is required to incorporate AJAX capabilities into an application.
A third version of this example adds AJAX support to a standard JavaServer Faces component through a servlet that interacts with the JavaServer Faces
component and other JavaServer Faces server-side objects to generate the appropriate auto completion data.
This entry focuses primarily on the question, "How can I incorporate AJAX functionality into a JavaServer Faces application?"
Among the other questions that this entry considers are the following:
 Should AJAX request handling be done in a separate servlet controller or should it be handled by the JavaServer Faces technology life cycle?
 How can existing components be AJAX-enabled without rewriting them?
 Should JavaScript code be embedded in Java code or externalized in a separate script file?
 How does the programming model differ between component writer and page developer?
 How should I organize the project structure in my workspace?
 How should I package the JavaServer Faces objects and JavaScript artifacts into a WAR file or EAR file?

Solution
Developers who want to include AJAX support in JavaServer Faces applications have more than one strategy to choose from. Which strategy they choose
depends on the needs of their situation. Developers might ask themselves the following questions to help them decide which strategy to select:
 Is this a new application or is the development team adding AJAX support to an existing JavaServer Faces application?
 Is the page author capable of adding the JavaScript and AJAX code to the page, or should it be handled by a server-side component so that the page
author can simply add the component tag to the page?
 Must the AJAX code be reusable?
 Must the AJAX code be customizable?
 Must the AJAX code be usable outside of the JavaServer Faces technology runtime?
 Is the application developer capable of doing the extra programming required to synchronize data with the JavaServer Faces objects if the development
team decides to de-couple the AJAX code from the JavaServer Faces runtime?
This entry discusses three strategies for incorporating AJAX support into a JavaServer Faces application. The first two strategies involve creating a custom
component to generate the necessary JavaScript and to make AJAX interactions with another server-side component. In Strategy 1, the JavaServer Faces
technology life cycle and the custom component handle the AJAX requests. In Strategy 2, the custom component communicates with a special servlet, which
handles all the AJAX requests. Strategy 3 does not require any custom components; all the additional AJAX support is performed by a servlet provided by the
developer.
Strategy 1 and Strategy 2 require knowledge of the JavaServer Faces technolgy life cycle to implement them. Strategy 3 requires knowledge of the Java servlet
API.
The following sections explain the three strategies and provide more detail on their advantages and disadvantages. After reading about these strategies and
answering the list of questions above, developers should be able to select the strategy that is appropriate for their particular situation. The Comparison of
Strategies section includes a chart that summarizes the characteristics of each strategy, which makes it even easier to make the decision.

Strategy 1: A Custom JavaServer Faces Component Renders Client-side AJAX JavaScript and Processes AJAX Requests

In this strategy the JavaServer Faces component does three things:


 Renders the HTML for the form elements
 Renders the links to the JavaScript code that handles the form events
 Processes AJAX requests

Figure 1 illustrates how this strategy works. The numbered steps following the figure explain what is happening in the figure.

https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 2 of 7

Figure 1: Architecture of a JavaServer Faces Component that Renders Client-Side AJAX JavaScript and Processes AJAX Requests
The following steps explain the architecture illustrated in Figure 1:
1. The page called Enter Address Page contains an HTML script element rendered by the renderer, AutoCompleteTextRenderer.
2. A call is made to the URL, faces/autocomplete-script, which is mapped to a FacesServlet instance. This instance processes the
RenderPhaseListener instance, which recognizes the URI and returns the component.js page containing the client-side JavaScript code
necessary for the AJAX interactions. After the component.js page is returned, the RenderPhaseListener instance stops taking part in the
JavaServer Faces technology life cycle processing for now.
3. When the user starts typing in the City text field, an onkeypress event occurs. The JavaScript function mapped to this event creates an
XMLHttpRequest object and configures it with the URL to the FacesServlet instance. This URL is faces/autocomplete&id=San. The
id=San part of the URL is a URL parameter in which San is the user input that is matched against the list of cities. The XMLHttpRequest object
makes a call to the FacesServlet instance. HTML page events continue to be processed by the JSP page.
4. The FacesServlet instance processes the RenderPhaseListener instance that recognizes the URL faces/autocomplete and looks up
the AutoCompleteTextField component, which provides the completion logic.
5. The RenderPhaseListener instance generates an XML document containing the potential completion items and returns it to the
XMLHttpRequest object, which then calls the XMLHttpRequest callback function.
6. The XMLHttpRequest callback function updates the HTML DOM based on the contents of the XML document that was returned.
7. After entering the form data, the user clicks the Update button and the form is posted using an HTTP POST to the FacesServlet instance,
which updates SessionBean with the address information entered by the user.

The remainder of this section provides further details on how this strategy works.
In Figure 1, the page called Enter Address Page is a JavaServer Faces page. This page contains a tag that represents the AutocompleteTextField
component, which is a JavaServer Faces component. This component renders two things: an HTML text field, into which the user enters the name of a
city, and the necessary client-side JavaScript AJAX code that fetches possible city names from a server-side managed bean. This managed bean
contains a method that implements the algorithm for completing city names.
To add the AJAX-enabled component to the application, the page author need only include the following tag in the page:

<ajaxTags:completionField size="40" id="cityField"


completionMethod="#{AutoCompleteTextfield.completeCity}"
value="#{SessionBean.city}" required="true"
/>

Code Example 1: Declaring an AJAX-enabled JavaServer Faces Component in a JavaServer Faces page
The AutoCompleteTextFieldTag tag handler implements the ajaxTags:completionField tag, which is rendered to HTML by the
renderer, AutoCompleteTextFieldRenderer. The first time the component is encountered in the page,
AutoCompleteTextFieldRenderer renders a reference to external JavaScript code, as shown in this HTML fragment:

<script type="text/javascript" src="faces/autocomplete-script">

Code Example 2: Rendered HTML that references JavaScript to be returned by RenderPhaseListener


When the reference to the external script file is reached, the browser makes a request to the URL, faces/autocomplete-script. The request first
goes to the FacesServlet instance and is then received by the RenderPhaseListener instance, which returns the client-side JavaScript relevant to
the AJAX interactions of the component. In the case of this example, the component.js file is included with the component and returned using the class
loader. Bundling the relevant JavaScript code with the component is a good practice because it keeps the script and component close to each other but
keeps the JavaScript out of the component code. The AJAX client-side JavaScript contains the XMLHttpRequest callback method, which includes the

https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 3 of 7

event mappings to the form elements rendered by AutoCompleteTextFieldRenderer.


When the target onkeypress event is encountered in the City form field, the client-side XMLHttpRequest object makes a HTTP GET call with the
partial text input from the field to the FacesServlet instance, which in turn calls the RenderPhaseListener instance. The
RenderPhaseListener instance looks up the AutoCompleteTextField component and gets a set of city names that match partial text input. For
example, if the user entered "San" into the field, the component would fetch the set of city names that start with the string "San".
At this point, the RenderPhaseListener instance can access the view state associated with the page if it is needed to process the interaction. When
processing AJAX requests with JavaServer Faces components, a developer can treat each AJAX request as a new request by using simple HTTP GET
calls. In this case, every request is a new Faces request. Or the developer can use POST calls, which give access to the view state associated with the
JavaServer Faces page. Strategy 1A provides further details on using POST calls to access view state. When using AJAX GET requests with JavaServer
Faces technology, a developer has access to managed bean components and has the ability to evaluate expressions but does not have access to the
view state.
In the case of this example, each auto complete AJAX request is a GET request and is therefore a new Faces request. The RenderPhaseListener
instance renders an XML response based on the results obtained from the AutoCompleteTextField component.
The server-side AJAX request processing is provided by a RenderPhaseListener instance. From the perspective of a server-side developer, the
requests are a little different from other AJAX requests in that they usually do not go through all the phases of the JavaServer Faces technology life cycle.
The following code shows how the RenderPhaseListener instance handles an AJAX request:

private void handleAjaxRequest(PhaseEvent event) {


FacesContext context = event.getFacesContext();
HttpServletResponse response =
(HttpServletResponse)context.getExternalContext().getResponse();
..
if ("complete".equals(action)) {
String method = request.getParameter("method");
try {
//get completion items
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
//Code to write XML response goes here...
event.getFacesContext().responseComplete();
return;
} catch (EvaluationException ee) {
ee.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}

Code Example 3: PhaseListener code to handle AJAX requests


One thing the developer needs to remember is that the content type must be set to "text/xml" and the Cache-Control header also needs to be set to
"no-cache" as shown in the following code snippet, which is taken from Code Example 3.

response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");

The call to event.getFacesContext().responseComplete() following the creation of the XML response causes the rest of the JavaServer
Faces life cycle to be skipped.
The response is returned to the XMLHttpRequest callback method, which updates the HTML DOM with the list of potential city names.
The end user might then select a relevant city name from the list returned from the AutoCompleteTextField component and click on the Update
button, which causes the form to be submitted to the FacesServlet instance, after which the SessionBean object is updated.

This strategy makes it easy for page authors to add AJAX-enabled components to a JavaServer Faces page. As long as the component is added to the
application, all they need to do is include the corresponding component tag in the page.
The component developer can make the component more customizable by allowing external JavaScript files to override the embedded file as well as
allowing the use of external style sheets. One way to do this is to include JavaScript and CSS properties on the component that the user can override. For
example, the AutocompletionTextField component can have an ondisplay property that lets users of the component specify JavaScript code
that is executed when an item is selected from the popup. Similarly, a selectedItemStyle property could let the user specify a CSS or a CSS style
class to be applied to selected items in the popup.

Strategy 1A: Doing AJAX processing against the full View

This approach is used by the AJAX Progress Bar for JavaServer Faces Technology. As with Strategy 1, FacesServlet is used to orchestrate all
the processing of AJAX requests and all the serving of script files. The main difference between Strategy 1 and Strategy 1A is the use of POST to
submit the actual view state back to the server. Doing this requires the AJAX-enabled components to abort normal page processing to prevent
rendering of the entire JSP page for AJAX requests. This is done the same way as in Strategy 1, using the responseComplete method on the
FacesContext instance. Another difference in the architecture of the progress bar example is that the PhaseListener instance is responsible
only for rendering the script, whereas ProgressBarRenderer writes out the response XML that is handled by the AJAX JavaScript code.
Another complexity resulting from the polling nature of the progress bar is the need for a closure to the function passed to the setTimeout

https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 4 of 7

JavaScript method. The progress bar uses the technique described by Richard Cornford at http://jibbering.com/faq/faq_notes/closures.html. This is
a very handy technique when coding AJAX-enabled components.
Performance should be considered when determining how much view state is associated with each request relative to the volume of AJAX requests being
processed when using this approach. While this approach is more tightly coupled with the JavaServer Faces life cycle and therefore provides ready
access to Faces objects, this tight coupling could result in a performance degradation compared to the strategy of using a separate AJAX controller, which
would not have a tight coupling to the view state.

Strategy 2: A Custom JavaServer Faces Component with Separate AJAX Controller

In this strategy the JavaScript rendered by the JavaServer Faces component communicates with a separate servlet. All asynchronous requests will
therefore be handled outside of the JavaServer Faces technology life cycle processing. However, the separate servlet can look up the FacesContext
instance and evaluate value binding and method binding expressions so that it can do such things as find managed beans and make calls to them.
Figure 2 illustrates this strategy. The numbered steps following the figure explain what is happening in the figure.

Figure 2: Architecture of a JavaServer Faces Component with separate AJAX Controller


The following list describes the interactions shown in Figure 2:
1. The page, called Enter Address Page, contains an HTML script element that is rendered by the renderer, AutoCompleteTextRenderer.
2. A call is made to the URL, faces/autocomplete-script, which is mapped to the FacesServlet instance. This instance processes the
RenderPhaseListener instance, which recognizes the URL and returns the component.js page containing the client-side JavaScript code
necessary for the AJAX interactions. After the component.js page is returned, the RenderPhaseListener instance stops contributing to the
JavaServer Faces technology life cycle processing for now.
3. When the user enters text into the City text field, an onkeypress event is generated. The JavaScript function mapped to this event creates an
XMLHttpRequest object and configures it with the URL to the AjaxControllerServlet instance. This URL is autocomplete&id=San.
The id=San part of the URL is a URL parameter in which San is the user input that is matched against the list of cities.
4. The XMLHttpRequest object makes the call to the AjaxControllerServlet instance, and HTML page events continue to be processed by
the page. The AjaxControllerServlet instance looks up the AutoCompleteTextField component and gets a list of potential
completion items.
5. The AjaxControllerServlet instance generates an XML document containing the potential completion items and returns it to the
XMLHttpRequest object. The XMLHttpRequest object then calls the XMLHttpRequest callback function.
6. The XMLHttpRequest callback function updates the HTML DOM with the list of city names, which are contained in the returned XML document.
At this point, users can select a city name, and when they do, the form element's value is set with the selected value.
7. After entering the form data, the user clicks the Update button and the form is POSTed to the FacesServlet instance, which updates the
SessionBean object with the address information entered by the user.
This strategy provides a clean separation of the AJAX interaction logic and the traffic that is usually handled by the FacesServlet instance. Each AJAX
request is a new request that the JavaServer Faces technology life cycle does not see, meaning that AjaxControllerServlet does not have access
to the JavaServer Faces page view state. The AJAX servlet can communicate with the managed beans and evaluate expressions by looking up the
FacesContext instance and calling the corresponding code.
The strategy is similar to Strategy 1 in that all "plumbing" is generated by the JavaServer Faces component itself. In this strategy, the JavaServer Faces
component is depending on a separate dedicated servlet to handle the JavaScript events it is adding to the rendered HTML. Updates to the JavaServer
Faces model data occur outside the scope of the JavaServer Faces technology life cycle request/response processing, and so care should be taken that
model data is consistent.

Strategy 3: Retrofitting an Existing JavaServer Faces Application

In this strategy, no custom JavaServer Faces components are used. As in Strategy 2, a separate dedicated AJAX servlet is used, and custom JavaScript

https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 5 of 7

code is added to the JSP page for the purpose of communicating with the servlet. Developers are responsible for all the "plumbing". This means that they
must provide the code that handles JavaScript events associated with the JavaServer Faces components, makes asynchronous calls, and updates the
HTML document when responses arrive.
Figure 3 illustrates this strategy. The numbered steps following the figure explain what is happening in the figure.

Figure 3: Retrofitting an Existing JavaServer Faces Application


The following steps explain the architecture of the JavaServer Faces application shown in Figure 3:
1. The page, called Enter Address Page, contains the client-side JavaScript code necessary for the AJAX interactions.
2. When the user types in the City text field, an onkeypress event is generated. The JavaScript function mapped to this event creates an
XMLHttpRequest object and configures it as a URL to the AjaxControllerServlet instance. This URL is autocomplete&id=San. The
id=San part of the URL is a URL parameter in which San is the user input that is matched against the list of cities. After the XMLHttpRequest
object makes the call to AjaxControllerServlet, the page continues to process HTML page events.
3. AjaxControllerServlet looks up the CitiesBean managed bean and gets a list of potential completion items.
4. The AjaxControllerServlet instance generates an XML document containing the potential completion items and returns it to the
XMLHttpRequest object. The XMLHttpRequest object calls the XMLHttpRequest callback function.
5. The XMLHttpRequest callback function updates the HTML DOM based on the contents of the XML document that was returned.
6. After entering the form data, the user clicks the Update button and the form is POSTed to the FacesServlet instance, which updates the
SessionBean object with the respective address information.
Figure 3 is very similar to Figure 2, which illustrates Strategy 2, with one exception: In Strategy 2, the servlet is provided with the JavaServer Faces
component and handles "generic" traffic. In Strategy 3, the JavaScript and the servlet are provided by the application developer. Notice that the servlet
talks about the application-specific list of cities, whereas in Strategy 2 the servlet handles generic items. This is because strategy 2 is designed to be
reusable in that the solution can be utilitzed to handle various auto completion use cases, such as completing city names, state names, or people names,
whereas Strategy 3 is bound to the specific use case of completing city names.
This strategy has the advantage of not relying on any special AJAX-enabled JavaServer Faces components, and therefore, any existing JavaServer
Faces application can be retrofitted with custom JavaScript and a special servlet to handle AJAX behavior. However, like Strategy 2, the use of a separate
servlet makes calling JavaServer Faces methods more difficult. Furthermore, it is impossible to get access to the view state of the JavaServer Faces
page.
This strategy allows for more customization of the JavaScript code that provides the AJAX interaction, but it is also more difficult to maintain and requires
that the page author be familiar with AJAX interactions and JavaScript. The page author is responsible for matching the events generated by the HTML
elements to the JavaScript functions. Doing this might be difficult for the average page author because the HTML elements are generated by a JavaServer
Faces component renderer, and therefore the page author must be somewhat familiar with the server-side renderer code. In addition, the page author is
also responsible for making sure that the AJAX updates to the HTML DOM match the HTML elements rendered by a JavaServer Faces component.
The application developer is responsible for the server-side processing of AJAX using a web component, such as a servlet. Updates to the JavaServer
Faces model data occur outside the scope of the JavaServer Faces technology life cycle request/response processing, so care should be taken to ensure
that model data updated by a server-side component is consistent with that managed by the JavaServer Faces technology runtime.

Comparison of Strategies

Below is a table that contains a list of trade-offs for each strategy.

Strategy 1: Custom JavaServer Strategy 2: Custom Strategy 3: No Custom JavaServer Faces


Faces Component that Renders JavaServer Faces Component: Developer-Managed JavaScript
Client-side AJAX Script and Component for and AJAX Servlet
Processes AJAX Requests separate AJAX

https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 6 of 7

Controller
Where do I put the In a PhaseListener instance. In a servlet or servlet In a servlet or servlet filter.
control logic? filter.
Does the page developer No. The JavaServer Faces component renderer will render the Yes. Additionally, care must be taken to ensure
need to provide client- necessary JavaScript. the form elements mapped to by the script match
side AJAX JavaScript those rendered by the target JavaServer Faces
and map to form component.
elements?
Is the solution re- Yes. However, the JavaScript included with the JavaServer Faces No. Each JavaServer Faces page would require its
usable? component must be written such that it can process requests own JavaScript. The JavaScript can be shared in a
from multiple components. There is a limited number of separate file, but portions such as the
XMLHttpRequest objects that can be used in a page, so care XMLHttpRequest callback function are generally
should be taken with the JavaScript in this case also. bound to a specific use case.
Is the solution Yes, provided the component provides customization hooks Yes, but that is the problem. Each JavaServer
customizable? Faces page contains a customized solution.
Does the component Yes, but there are subtle differences in No No
have access to the view how the view state can be made
state of a JavaServer accessible depending on the version of
Faces page? the JavaServer Faces technology
runtime you are using.
Can the AJAX control Yes. The control logic is in a Yes. The controller is a servlet that can be modified or replaced.
logic for a JavaServer PhaseListener instance, which would
Faces component be need to be replaced. This would require
overridden? repacking the component.
Can the AJAX control Yes. Each request is a JavaServer Faces Yes. The AJAX control logic code can access managed beans and evaluate
logic access managed request that has ready access to expressions by looking up the FacesContext instance. This requires a few
beans and evaluate managed beans and expressions. lines of code.
expressions?
Can I leverage existing Yes. Either the JavaScript must be embedded with the Yes.
JavaScript libraries? JavaServer Faces component or the component must be capable
of using external JavaScript.
Can I leverage the AJAX No. No. Yes. Servlets and servlet filters do not require a
control logic outside a JavaServer Faces technology runtime; although, if
JavaServer Faces portions of the AJAX control logic are bound to
technology runtime? managed beans or are evaluating expressions in
the JavaServer Faces technology runtime, this
would not be possible.

Rendering JavaScript Exactly Once

The JavaScript should be placed in a separate file as mentioned above, to ensure that the JavaScript contents can be cached by the browser.
While the JavaServer Faces component can be used multiple times in a page, the JavaScript inclusion reference should be emitted exactly once -- before the first
usage. A good way to do this is to modify the renderer that emits the script tag so that it stores a flag for itself in the request map. This flag records whether
the renderer has written the script out for the current page yet. The following code snippet demonstrates how to add code to the renderer that will store the flag
and check its value to determine if the script tag has been rendered:

...
private void renderScriptOnce(ResponseWriter writer, UIComponent component, FacesContext context)
throws IOException {
// Store attribute in request map when we've rendered the script such
// that we only do this once per page
Map requestMap = context.getExternalContext().getRequestMap();
Boolean scriptRendered = (Boolean)requestMap.get(RENDERED_SCRIPT_KEY);

if (scriptRendered == Boolean.TRUE) {
return;
}
// Render script and CSS here
...
}
private static final String RENDERED_SCRIPT_KEY = "bpcatalog-ajax-script-rendered";

Project Structure and Packaging

One issue that developers must deal with is how to organize their workspace. What should the project conventions be? Generally, this is covered by existing
project conventions for JavaServer Faces technology modules and applications. For example, the faces-config.xml file and the TLD files for JavaServer
Faces technology are usually kept in the src/conf directory.

But where should you keep the JavaScript files? Should they be kept with the source code files? In most cases, we recommend that the JavaScript files be kept
in the src/resources directory. In some cases, you might be using a pre-existing library of JavaScript files, which might be reusable even without the
JavaServer Faces components, such as in the case of making a JavaServer Faces component that uses some of those existing JavaScript files. In this instance,
the JavaScript library should be viewed as a separate project and should be used only by the JavaServer Faces application.

https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008
bpcatalog: bpcatalog: Using JSF with AJAX Page 7 of 7

Another issue to consider is how to package these JavaServer Faces components and JavaScript artifacts into a WAR file or EAR file. The packaging is mostly
the same as for other JavaServer Faces modules and applications, but you need to consider where to put the AJAX artifacts, which include the javascript files.
Generally, it is recommended that you place the AJAX artifacts with the compiled classes so that the JavaServer Faces components can load them by calling
getClass().getResourceAsStream().
In order to use the components within an IDE, there are additional packaging considerations, such as how to make properties visible in IDE property sheets.
These considerations differ from IDE to IDE (until this hopefully gets standardized with JSR 273). For a description of how to package your JavaServer Faces
component for Sun Java Studio Creator, read http://developers.sun.com/prodtech/javatools/jscreator/reference/techart/jsfcomplibrary.html .

Helpful Hints for Developing AJAX components with JavaServer Faces Technology

 Understand the JavaServer Faces component model. The J2EE 1.4 Tutorial on Creating JavaServer Faces Components describes the necessary artifacts
needed to create custom JavaServer Faces components.
 Get a good JavaScript book. JavaScript: The Definitive Guide, 4th Edition By David Flanagan is quite adequate.
 Get familiar with Venkman, the JavaScript debugger in the Mozilla suite.
 Get familiar with the Internet Explorer Script Debugger.
 Visit QuirksMode.org, a great JavaScript/CSS reference site.
 It's generally a good idea to put all your JavaScript code into one file that is referred to using <script> tags. During iterative development, it's a good idea
to place this file directly in your server root so you can edit it in place. Then modify your code to refer to it at this location, just during development. When
you get everything working, you can switch to using the FacesServlet and PhaseListener style to keep things self contained.

References

For more details on this solution see the following


 JavaServer Faces Technology Auto-Completion Component with AJAX: Design Details
 AJAX Progress Bar for JavaServer Faces Technology: Design Details.

© Sun Microsystems 2005. All of the material in The Java BluePrints Solutions Catalog is copyright-protected and may not be published in other works without express written
permission from Sun Microsystems.

https://bpcatalog.dev.java.net/ajax/jsf-ajax/ 1/25/2008

You might also like