The AjaxComponent strategy for JSF: The best of both worlds
Adding Ajax capability to JSF applications is easy to talk about but not so simple to do. Developing a custom lifecycle phase is too complex for most needs; putting the handler code in the component's decode()
method doesn't give you enough control; and using a phase listener by itself breaks encapsulation. In this article, Matt Tyson demonstrates the AjaxComponent strategy -- an effective and practical way of integrating Ajax into your JSF applications, and easily extensible to boot.
If you want to handle Ajax requests in JavaServer Faces (JSF) applications, you'll probably start with a handful of popular approaches and quickly realize that each one has its advantages and disadvantages. For instance, if you use a component to set up and handle an Ajax request, you remain within the JSF component model and keep all the code related to the request encapsulated. If you use a phase listener as a kind of proxy to delegate to the component, you can invoke a specific method on the component, avoid invoking other components unnecessarily, and avoid issues with the immediate attribute.
Normally, if you just use a component to handle an Ajax request, you would put the Ajax code in one of the component's standard JSF methods (like decode()
) and allow JSF to execute it in the normal course of the request processing lifecycle, but this doesn't give you enough control. On the other hand, if you were to use a phase listener alone, you would break encapsulation by putting unrelated logic in the phase listener. You can think of the component as achieving the where that you want, and of the phase listener as getting you the when that you want.
If you combine the component and phase listener approaches, you get both the when and the where, and you can also add new Ajax-enabled components to your application with ease. Moreover, you keep the components' standard request processing and Ajax processing nicely separated. The JSF Ajax component implements an interface with a single method, handleAjaxRequest()
, which the phase listener invokes. This component interface, and the combined strategy, is called the AjaxComponent. Using it, you gain the simplicity of a component and the power of a phase listener. The combined approach you'll learn about in this article is very effective and practical for most applications, and is easily extensible, too.
When you need to Ajax-enable a JSF component, AjaxComponent is a solid strategy for doing it. AjaxComponent also works seamlessly with the JSF AjaxCommand strategy described in my previous JavaWorld article.
The pieces of the puzzle
Building a JSF component involves a fair amount of overhead. It might even bring to mind the process of creating EJBs. It looks as if this problem will be addressed in JSF 2.0, but for now, with JSF 1.1, we're still stuck with a multi-step process. On the positive side, these steps bring you a reusable component that can be accessed with a simple tag in your JSPs. Moreover, components can be, and are, shared among developers -- just take a look at the Apache Tomahawk Trinidad and Tobago projects.
The following elements are required to build a JSF component, and the AjaxComponent
is no exception. The file in parentheses is the element as it exists for the example AjaxComponent that you'll see built in the course of this article. (See Resources to download the complete code for this application.)
- A
Component
class (AjaxComponent.java) - A
Renderer
(AjaxComponentRenderer.java) - A tag handler class (AjaxComponentTag.java)
- A tag descriptor file entry (Tutorial.tld)
- An entry in faces-config.xml
The sample application includes an AjaxComponent
with all of the above elements. Note that the application uses MyFaces 1.1.5 and the Dojo JavaScript library.
The best way to get a good understanding of how the AjaxComponent strategy works is to examine each of the elements listed above in turn. After that, I'll wrap up by describing how to deploy the sample application and some changes that a production component might require.
The Component class and the AjaxInterface
Let's begin with the extremely simple and essential interface: the AjaxInterface
, shown in Listing 1. This is the interface that will be implemented by the sample JSF component you'll build over the course of this article.
Listing 1. The AjaxInterface
public interface AjaxInterface {
public void handleAjaxRequest(FacesContext context);
}
Nice and simple, just how we like it.
If you are familiar with how the JSF component model works, you know that the Component
class is essentially a state-holding mechanism, and the real work is done by the Renderer
. The Component
class defines what the Component
is, while the Renderer
defines what it does. (Just to avoid confusion, I should point out that when people talk about a JSF component in general, they usually mean the whole bundled thing: the Component
class, the Renderer
, tag handler, and so on, as opposed to the Component
class alone.)
Now take a look at the Component
class itself, shown in Listing 2.
Listing 2. The Component class
public class AjaxComponent extends UIComponentBase implements AjaxInterface {
private static final transient Log log = LogFactory.getLog(tutorial.jsf.ajax.component.AjaxComponent.class);
public static final String DEFAULT_RENDERER_TYPE = "tutorial.jsf.ajax.component.AjaxComponentRenderer";
public static final String COMPONENT_FAMILY = "tutorial.jsf.ajax.component.AjaxComponent";
public static final String COMPONENT_TYPE = "tutorial.jsf.ajax.component.AjaxComponent"; // Used by Tag Handler
public AjaxComponent() {
this.setRendererType(AjaxComponent.DEFAULT_RENDERER_TYPE);
}
public String getFamily() {
return COMPONENT_FAMILY;
/**
* This method is executed by the Ajax listener when an Ajax call for this component is detected.
*/
public void handleAjaxRequest(FacesContext context){
// Delegate to the Renderer
AjaxRendererInterface renderer = (AjaxRendererInterface)this.getRenderer(context);
renderer.handleAjaxRequest(context, this);
}
}
Again, this is a very simple class. Of course, much of the complexity exists in the UIComponentBase
base class; but the work you'll be concerned with is just delegated to the Renderer
, in order to keep the code that handles the request in the same place as the code that sets up the request.
The Renderer and AjaxRendererInterface
The Renderer
in a JSF component is responsible for outputting whatever is necessary to display the component, and for handling the input coming from the user for that component. In this case (and for most cases, really), the output is HTML and JavaScript. For the standard (non-Ajax) request processing, the decode()
method processes the input. In this case, as you saw above, the component delegated the handling of the Ajax response to the renderer.
Again, the AjaxRendererInterface
defines one method, handleAjaxRequest()
. Listing 3 demonstrates how that method works.
Listing 3. The Renderer: handleAjaxRequest()
public void handleAjaxRequest(FacesContext context, UIComponent component){
if (log.isInfoEnabled()) { log.info("BEGIN handleAjaxRequest()"); }
HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
String textField = request.getParameter(INPUT_NAME);
String serverContribution = "SERVER RESPONSE: ";
StringBuffer xml = null;
if (textField == null){
if (log.isInfoEnabled()) { log.info("No parameter found for text field."); }
} else {
if (log.isTraceEnabled()) { log.trace("textField: " + textField); }
// We now have the new value entered by the user
// Now we create our XML response
xml = new StringBuffer("");
xml.append("" + serverContribution + textField + " ");
xml.append("OK ");
}
if (xml == null){
if (log.isInfoEnabled()) { log.info("Response is null."); }
xml = new StringBuffer(this.getErrorString());
}
// Now we are ready to send the response
HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
response.setContentType("text/xml");
response.setHeader("Cache-Control", "no-cache");
try {
response.getWriter().write(xml.toString());
if (log.isInfoEnabled()) { log.info("Response sent: " + xml); }
} catch (IOException e){
if (log.isErrorEnabled()) { log.error("Error writing ajax response.", e); }
}
}
protected String getErrorString(){
return new String("There was a problem ERROR ");
}
Remember, the handleAjaxRequest()
method is invoked when the user has submitted an Ajax request to the component. The method is responsible for doing everything necessary, both receiving data and formulating the response. This sample method is very simple, but it communicates the idea that you get some data from the user, do some processing on the server, and return a response. All this method does is take whatever the user sent and return it back as SERVER RESPONSE:
to demonstrate that the server had its say.
The technique for packaging the response is interesting. You wrap it in XML, which the front-end JavaScript is expecting. The whole response is framed in
tags; in addition to the
, it includes a
element. You can see that the response can be as simple or involved as the situation merits.
If anything goes wrong, you need to prepare an appropriate response, with its status set to ERROR
.
Finally, you take the XML string and send it off to the JavaScript that initiated the call. The request processing is then complete.
Notice that you did not call FacesContext.responseComplete()
anywhere; that's because you know that it was called by the PhaseListener
that invoked this method in the first place. You'll see that happen when you take a closer look at the PhaseListener
.
Setting up the Ajax Request: The encodeBegin() method
Next, you'll see how the renderer outputs itself with the ability to make the Ajax call. This simple example only requires the encodeBegin()
method, illustrated in Listing 4.
Listing 4. The Renderer: encodeBegin()
private static final String INPUT_ID = "tutorial.jsf.ajax.component.INPUT";
private static final String INPUT_NAME = "tutorial.jsf.ajax.component.INPUT"; // This will be the text field key in the request
private static final String BUTTON_ID = "tutorial.jsf.ajax.component.BUTTON";
private static final String MESSAGE_DIV_ID = "tutorial.jsf.ajax.component.MESSAGE_DIV";
private static final String CLIENT_ID = "tutorial.jsf.ajax.component.CLIENT_ID";
//...
public void encodeBegin(FacesContext context, UIComponent component) throws IOException{
if (log.isTraceEnabled()) { log.trace("begin encodeBegin()"); }
HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
AjaxComponent ajaxComp = (AjaxComponent)component;
ResponseWriter out = context.getResponseWriter();
String clientId = ajaxComp.getClientId(context);
out.startElement("div", ajaxComp);
out.writeAttribute("id", clientId, null);
out.writeAttribute("style", "border:solid; width:200; height:200;", null);
out.startElement("div", ajaxComp); // Message div
out.writeAttribute("id", MESSAGE_DIV_ID, null);
out.endElement("div"); // Message div
out.startElement("input", ajaxComp);
out.writeAttribute("type", "text", null);
out.writeAttribute("id", INPUT_ID, null);
out.writeAttribute("name", INPUT_NAME, null);
out.endElement("input");
out.startElement("button", component);
out.writeAttribute("type", "button", null);
out.writeAttribute("name", BUTTON_ID, null);
out.writeAttribute("id", BUTTON_ID, null);
out.writeAttribute("value", BUTTON_ID, null);
out.writeText("Ajax It", "null");
out.endElement("button");
// A hidden field to hold the URL of the server for the ajax request
out.startElement("input", ajaxComp);
out.writeAttribute("id", "tutorial.jsf.ajax.component.SERVER", null);
out.writeAttribute("type", "hidden", null);
out.writeAttribute("value", request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getRequestURI(), null);
out.endElement("input");
// A hidden field to hold the component Client ID
out.startElement("input", ajaxComp);
out.writeAttribute("id", CLIENT_ID, null);
out.writeAttribute("type", "hidden", null);
out.writeAttribute("value", clientId, null);
out.endElement("input");
out.write("AjaxComponentn");
out.startElement("script", ajaxComp);
out.write("dojo.addOnLoad(AjaxComponent.loadComponent());n"); // Sets up the client side JS
out.endElement("script");
}
Most of this code is standard JSF Renderer
fare. It outputs HTML that displays what you want. Notice, however, that it's careful to give every element you're interested in a distinct name. That's what all those String
constants are for. This is important, because you're going to need to find these elements again in the client-side JavaScript.
Notice also that one bit of information sent is the URL of the server; this tells your JavaScript where to send its eventual Ajax call. Another piece of information is the JSF clientId
. You will see that this is used later by the PhaseListener
. Both of these are written to hidden fields, where the user can't see them, but they are available to the JavaScript.
This is the critical line:
out.write("dojo.addOnLoad(AjaxComponent.loadComponent());n");
This code uses the Dojo JavaScript library to add an onLoad
listener that calls a method once the page has loaded. Note that the component requires that the JavaScript function AjaxComponent.loadComponent()
be available! In other words, the page using the AjaxComponent
tag must include the JavaScript file with the AjaxComponent
JavaScript.
There are more sophisticated means of incorporating JavaScript (and CSS) files into the component that avoid the JSP include. If you are using MyFaces, you can use the AddResource mechanism, but be aware that this will couple your component to the MyFaces implementation. Another strategy you might be interested in is the use of Weblets. For simplicity's sake, though, this example will just include the JavaScript file in the JSP.
The client side: AjaxComponent.loadComponent()
Take a look at the loadComponent()
function in Listing 5. Keep in mind how this function is invoked. After the HTML page has been rendered, along with all the elements of the component, the function will be called.
Listing 5. JavaScript: AjaxComponent.loadComponent()
AjaxComponent.loadComponent = function(){
// Get the Server
var serverField = document.getElementById("tutorial.jsf.ajax.component.SERVER");
AjaxComponent.server = serverField.value; // Save the server for use in ajax call
// Get the output message div
var msgDiv = document.getElementById("tutorial.jsf.ajax.component.MESSAGE_DIV");
AjaxComponent.messageDiv = msgDiv; // This is the actual domNode
// Get the output message div
var clientId = document.getElementById("tutorial.jsf.ajax.component.CLIENT_ID");
AjaxComponent.clientId = clientId.value;
// Get the button
var button = document.getElementById("tutorial.jsf.ajax.component.BUTTON");
// Use dojo to add an event handler -- like onClick="..." but handles cross browser issues
dojo.event.connect(button, "onclick", AjaxComponent, "onButtonClick");
}
You can see that this function's job is to find every important element of the component by the IDs you gave it in the Note that as written, it is not safe to use multiple instances of the component on the same page. That's because there's nothing to distinguish the elements of different component instances from each other. You can overcome this by incorporating the Using So now you've gotten to the point where the user has clicked on the button. When that happens, the JavaScript executes the Here again you leverage Next, you compose an associative array. This array holds the request parameters that you want to send, along with the request. The first parameter tells the It's worth mentioning here that you can send any number of parameters along to help direct the processing that takes place on the server, including different kinds of requests issued by your component if need be. For example, different button clicks might require different responses, in which case you would send along a parameter declaring which button was clicked. Now you're ready to send the request. You use a Before you can use your new The You do have to declare here the component type that the handler is for, and what the renderer type is. This will become important later when you declare the component in faces-config.xml. Now you declare the tag in a taglib entry, as in Listing 8. Listing 8 includes the entire taglib file from the example app. You just need to place this somewhere on the classpath, usually in the WEB-INF directory. You might wonder what all these attributes are doing in the listing, given I just said that we don't have any, and that's why the tag handler class is so simple. Those attributes belong to the Now you are finally ready to declare the component for use in the application. You can see in the example application that the faces-config.xml file, part of which is shown in Listing 9, is also deployed inside the WEB-INF folder. JSF automatically searches for that file to configure itself. (It also looks for the file inside the META-INF folder of JAR files, which allows you to package your component descriptors along with the components). Remember also that you declared the type and renderer-type in the tag handler. Getting this configuration step just right, though simple, can sometimes be a little touchy. Make sure the strings you use on the component and tag handler match what you declare in faces-config.xml, and also that the classnames are exactly right. Remember that you've also declared a phase listener in the Implementing The reason you choose Take a look at Listing 11 in more detail. I've annotated the code with some commented numbers that I'll use to direct your attention to particularly interesting sections. In line 1, you check for the request parameter denoting this as an Ajax request. Remember back in the JavaScript, when you added that to the parameters of the Ajax call? If that parameter is not found, you immediately leave the phase listener and allow the regular lifecycle to proceed. If, on the other hand, you do find the Ajax request parameter, you first call Next, you get the Line 3 shows how you can recover the Next, you check to make sure the component was found. If not, something has gone awry. Perhaps the At line 4, once the component is found, you execute the You've also seen how the JavaScript Parsing XML in JavaScript can be a little finicky. Still, you can see what's going on here. You get what was sent in the The example application uses Maven 2 for its build tool. Once you've got Maven installed, browsing to the root of the application and typing If you are familiar with Ant, Maven can take a little getting used to, but it saves time by defining a typical structure for things (like a Web app) and automating tasks around that structure. If you develop with Eclipse, note that you can tell Maven to build all your .project and .classpath files by using The Maven repository holds all the files that your builds have requested. The first time you request a file, it has to go out to the Internet to find it, using the artifact ID and version provided in pom.xml. The latter file is what defines the build process. (This quick description isn't intended to be thorough; if you need more information on Maven, see the Resources section.) Once you've run The AjaxComponent strategy described here is very effective for use in production components. Using this technique, you can add Ajax capability to JSF components relatively easily, and keep all of your input/output logic nicely packaged in the renderer. Once the phase listener is set up, it's very easy to add more components that use the strategy -- in fact, you don't even have to touch the listener. If you find that putting the request handling logic into the component itself doesn't really make sense, then you should probably use the JSF AjaxCommand strategy instead. You can even use the same phase listener. With the two strategies in place, you are ready to handle any kind of Ajax request from your JSF application. A good guideline for choosing between these two strategies is to ask yourself whether the functionality you are providing will be required by just one component, or many. If the answer is many, then your application is a good candidate for an As always, let me know your experience and thoughts. Join the discussion below to let me know what you think! Matt Tyson has been building Java Web applications for 10 years. He runs a software consultancy called Odyssey Design and Development, Inc.
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/71047/viewspace-996757/,如需轉載,請註明出處,否則將追究法律責任。
encode()
method. First you get and save the server URL. Next, you grab the domNode
of the clientId
. Finally, you get the button element, and attach an event listener to it. cleintId
(which is always unique for every component on the page) into the IDs of the elements you need to get. dojo.event.connect()
to add your JavaScript event listener means that you don't have to worry about cross-browser concerns. This method says that for the domNode
in the variable button
, you'll add an onclick
listener that invokes the AjaxComponent.onButtonClick()
function. (Note that the connect method has a three-argument version that you can use if your handler function isn't a method on an object like AjaxComponent
.) AjaxComponent.onButtonClick()
function, shown in Listing 6. Listing 6. JavaScript: AjaxComponent.onButtonClick() event handler
AjaxComponent.onButtonClick = function(evt){
// Get the input text field
var input = document.getElementById("tutorial.jsf.ajax.component.INPUT");
AjaxComponent.inputField = input.value;
// Build the request params
var params = {
"tutorial.jsf.ajax.AJAX_REQUEST" : "true",
"tutorial.jsf.ajax.component.INPUT" : AjaxComponent.inputField,
"tutorial.jsf.ajax.AJAX_CLIENT_ID" : AjaxComponent.clientId
};
// Send ajax request
dojo.io.bind({
url: AjaxComponent.server,
method: "GET",
load: function(type, data, evt){
AjaxComponent.onAjaxResponse(data);
},
mimetype: "text/xml",
content: params
});
}
dojo
to make the Ajax call painless. First, you get the element that contains the text entered by the user, and hold onto its value in the
inputField
variable. PhaseListener
(which you'll see in more detail shortly) that the request is an Ajax request. The second parameter contains the user input. The third and final parameter communicates to the PhaseListener
the component that made the request. dojo.io.bind()
call, which has an associative array for its argument. url
element tells the request where to go. Use the server URL you saved earlier. method
defines that kind of request that you're sending (use POST if your request might get large). load
defines the function that's responsible for handling the response from the server. You use the function to delegate to your own function, passing in the data
argument, which contains the actual data from the server (in this case, the XML that you prepared in the handleAjaxRequest()
method of the AjaxRenderer
). mimetype
is important in identifying the kind of data that is being sent. context
holds the parameters you prepared earlier. The tag handler class and taglib descriptor
AjaxComponent
tag in a JSP, you need to create a tag handler for it, and also declare it in a taglib file. AjaxComponentTag
class, shown in Listing 7, is very simple, because there are no attributes to manage on the tag. If there were, this is where you'd pass them on to the component itself. Listing 7. The tag handler: AjaxComponentTag
public class AjaxComponentTag extends UIComponentTagBase {
private static final transient Log log = LogFactory.getLog(tutorial.jsf.ajax.component.AjaxComponentTag.class);
public AjaxComponentTag() {
}
public String getComponentType() {
return AjaxComponent.COMPONENT_TYPE;
}
public String getRendererType() {
return AjaxComponent.DEFAULT_RENDERER_TYPE;
}
}
Listing 8. The tag library descriptor
tlib-version>1.3
UIComponent
interface and are handled by the base classes you've extended (UIComponentBase
and UIComponentTagBase
). Because tag descriptors do not support inheritance, you must declare them here for your tag. faces-config.xml
Listing 9. faces-config.xml component and phase listener entries
odewrap">
public static final String DEFAULT_RENDERER_TYPE = "tutorial.jsf.ajax.component.AjaxComponentRenderer";
public static final String COMPONENT_FAMILY = "tutorial.jsf.ajax.component.AjaxComponent";
public static final String COMPONENT_TYPE = "tutorial.jsf.ajax.component.AjaxComponent"; // Used by Tag Handler
public AjaxComponent() {
this.setRendererType(AjaxComponent.DEFAULT_RENDERER_TYPE);
}
public String getFamily() {
return COMPONENT_FAMILY;
}
The PhaseListener
lifecycle
element. That phase listener is the key to the whole process. Listing 11 includes the whole class. Listing 11. The PhaseListener class (AjaxListener)
package tutorial.jsf.ajax;
// Imports exluded ...
public class AjaxListener implements PhaseListener {
private static final transient Log log = LogFactory.getLog(tutorial.jsf.ajax.AjaxListener.class);
// These constants are used to get values from the request params
// Determining if the request is an AjaxComponent and what the client id of the component
// making the request is, respectively.
private static final String AJAX_PARAM_KEY = "tutorial.jsf.ajax.AJAX_REQUEST";
private static final String AJAX_CLIENT_ID_KEY = "tutorial.jsf.ajax.AJAX_CLIENT_ID";
public AjaxListener() {
}
/**
* Handling the any potential Ajax component requests after the Restore View phase makes the restored view
* available to us. Therefore, we can get the component (which made the request) from the view,
* and let it respond to the request.
*/
public void afterPhase(PhaseEvent event) {
if (log.isInfoEnabled()) { log.info("BEGIN afterPhase()"); }
FacesContext context = event.getFacesContext().getCurrentInstance();
HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
String ajaxParam = request.getParameter(AJAX_PARAM_KEY);
// Check for the existence of the Ajax param
if (ajaxParam != null && ajaxParam.equals("true")){ // 1
if (log.isInfoEnabled()) { log.info("This is an ajax request."); }
context.responseComplete(); // Let JSF know to skip the rest of the lifecycle
String componentId = request.getParameter(AJAX_CLIENT_ID_KEY); // Get the Ajax component ID
if (componentId == null){ // 2
if (log.isWarnEnabled()) { log.warn("No Client ID found under key: " + componentId); }
} else {
handleAjaxRequest(context, componentId);
}
// Save the state of the page
context.getApplication().getStateManager().saveSerializedView(context);
}
}
protected void handleAjaxRequest(FacesContext context, String ajaxClientId) {
UIViewRoot viewRoot = context.getViewRoot();
AjaxInterface ajaxComponent = null;
try {
ajaxComponent = (AjaxInterface)viewRoot.findComponent(ajaxClientId); // 3
} catch (ClassCastException cce){
throw new IllegalArgumentException("Component found under Ajax key was not of expected type.");
}
if (ajaxComponent == null){
throw new NullPointerException("No component found under specified client id: " + ajaxClientId);
}
ajaxComponent.handleAjaxRequest(context); // 4
}
public void beforePhase(PhaseEvent arg0) {
// We do nothing in the before phase.
}
public PhaseId getPhaseId() {
return PhaseId.RESTORE_VIEW;
}
}
PhaseListener
requires only three methods. The first thing to decide is what phase the listener will affect. For the AjaxComponent
, you want the RESTORE_VIEW
phase. After that, you need to decide whether to execute before or after the phase (or both before and after, if need be). RESTORE_VIEW
is that it's the first phase; because you're handling an Ajax request, you want to avoid the rest of the JSF processing lifecycle. You use the afterPhase()
method because you need the view to be restored, and thus make the component available to use, to handle the request. FacesContext.requestComplete()
. That means that as soon as this phase is done, Ajax will skip any more processing. clientId
from the request. That was also sent with the Ajax call. In line 2, you check to make sure that it was found. If not, that means the request was set up wrong, and was flagged as an Ajax call, but no component clientId
was sent. On the other hand, if the clientId
is found, you call handleAjaxRequest()
. AjaxComponent
from the view. JSF maintains each view as a hierarchical model, and every component can find its children via the findComponent()
method. So you get the root of the view, and use find component to get the component that made the request. clientId
was not correct, or maybe you somehow haven't gotten the right view back. That can happen if you sent the request to a different URL than the one that set it up. In that case, JSF will create a new view tree -- one that doesn't have your component in it. handleAjaxRequest()
. That brings you back to where you began. You've already seen how the component delegates to the renderer, and the renderer then returns an XML response. onButtonClick()
method used dojo.io.bind()
to set the AjaxComponent.onAjaxResponse()
function to handle the response. You can see how the onAjaxResponse()
actually does this in Listing 12. Listing 12. Handling the XML response back from the server: AjaxComponent.onAjaxResponse()
AjaxComponent.onAjaxResponse = function(responseXml){
var status = responseXml.getElementsByTagName("status")[0].childNodes[0].nodeValue;
var msg = responseXml.getElementsByTagName("message")[0].childNodes[0].nodeValue;
var style = "";
if (status != "OK"){
style = "color: red;";
}
var msgNode = document.createTextNode(msg);
var para = document.createElement("p");
para.setAttribute("style", style);
para.appendChild(msgNode);
AjaxComponent.messageDiv.appendChild(para);
}
element, and create a style based on that. Then you create a paragraph element, give it the style, and append the text from the
tag. Finally, using the domNode
you saved when you rendered the component, you append the new paragraph element to the message Building and deploying the sample application
mvn clean install
will compile the class files and package them into a WAR file, along with the descriptors and config files from the webapp directory. mvn eclipse:eclipse
. You should also be aware that when Maven generates these files, it uses an environment variable called M2_REPO that you'll want to add to Eclipse. M2_REPO points to the root of the Maven repository. mvn clean install
, the WAR file is ready for deployment. You can find it in the target directory, as jsf-ajax-component-1.0.0.war. Just copy the WAR file into Tomcat's webapp directory, and browse to .
The best of both worlds
AjaxCommand
, since you will then be able to share the functionality across all the components without duplicating the code. Otherwise, go with the AjaxComponent
, and keep the code tight and encapsulated. Author Bio
最新文章
相關文章
- Master of Both —— Trie的應用AST
- Table is specified twice, both as a target for 'UPDATE' and as a separate source
- ***** JSF專集 *****JS
- JSF和strutsJS
- JSF vs StrutsJS
- Best Practice in Writing
- ALTER SYSTEM 中 SCOPE=SPFILE/MEMORY/BOTH 的區別:
- jsf與jspJS
- JSF效能問題JS
- JSF的問題JS
- 破破的JSFJS
- Jsf國際化JS
- NetBeans能否承載JSF中興之重? JSF開發工具BeanJS
- Load a script file in sencha, supports both asynchronous and synchronous approachesAPP
- Best Team With No Conflicts
- Mobile Web Best Practices 1.0Web
- The best LeetCode NodesLeetCode
- JSF的框架相關JS框架
- JSF 中如何分模組??JS
- JSF技術介紹JS
- JSF的中文問題JS
- 網易推出全新工作室Worlds Untold,動作冒險遊戲在研遊戲
- The Best Image Ocr SDK For BAT.BAT
- He also has best iphone casesiPhone
- 矩陣樹定理 BEST 定理矩陣
- 有jsf的應用嗎JS
- 請教jsf和elipseJS
- JSF中的設計模式JS設計模式
- Facelets是JSF更好的外衣JS
- JSF與Struts的異同JS
- The Best Way to Export an SVG from SketchExportSVG
- Best Time to Buy and Sell Stock系列分析
- css best practice for big team and projectCSSProject
- 80 of the Best Linux Security ApplicationsLinuxAPP
- Data Guard Switchover and Failover Best PracticesAI
- 矩陣樹定理與BEST定理矩陣
- [ARC060F] Best Representation
- 策略模式(Strategy)模式