Ajax and JSF, Joined At Last
Join the DZone community and get the full member experience.
Join For FreeIn part four of this series on JavaServer Faces (JSF) 2.0 features contributed by Red Hat, or in which Red Hat developers played a significant role, co-author Dan Allen and I are going to focus on the new Ajax functionality in JSF 2.0. We’ll go over the examples and explain the inspirations. As with the rest of this series, we’ll also give you insights and explanations you may not find in other articles or blog entries.
Editor's Note: JSF 2.0 is available in AS6 M1, and will be supported by Red Hat in the JBoss Enterprise Application Platform in the near future.
Read the other parts in this article series:
Part 1 - JSF 2: Seam's Other Avenue to Standardization
Part 2 - JSF 2 GETs Bookmarkable URLs
Part 3 -
Part 4 -
Part 5 -
Introduction
Where shall we begin with JSF and Ajax? There's certainly a history there that reads like a romance novel. You find JSF and think you're in love. It adds structure and stability to the crazy web development scene. But it's missing something you crave: Ajax. All is not lost, though, because you find a rich component library on the side, like RichFaces, that satisfies your hunger. Sure, the arrangement is cushy, but you feel like you are using it for its Ajax. Then one day, JSF 2 is released, and you are swept off your feet. True happiness at last. Not only does the new JSF have Ajax built in, it wants you to see other component libraries too. You're no longer stuck with a single relationship! A fantasy come true.
Why Ajax now and not before?
Although Ajax is ubiquitous today, and you could not imagine the Web without it, it was all very new and revolutionary when the first two JSF specifications were published. Before the Ajax component libraries started to crop up, using Ajax with JSF probably meant using JSF incorrectly.
Early JSF adopters found themselves in a real fix when Ajax started to hit big. The model just didn't seem to support it. Those developers struggled trying to figure out how to make JSF work with Ajax.
Perhaps you can recall crafting JavaScript functions that would emulate a JSF form submission and then stitch the page updates back into the page manually. On postback, JSF would be utterly confused because the rendered view didn't match the component tree (and new form elements were appearing). It's one of those "I'll show you my scary JSF Ajax code if you show me yours." scenarios. Here are some examples:
invokeAction : function(targetDoc) { this.mergeValues(targetDoc); JSFUtils.invokeActionOnComponent( targetDoc.getElementById("workspaceForm:addLineItem")); }, <script type="text/javascript"> new Ajax.Autocompleter( 'workspaceForm:worksheet:#{index}:name', 'nameOptions_#{index}', #{fn:encodeUrl("/ajax/auto_complete_values.jsf")}', {paramName: 'q', onHide: function(element, update) { new Effect.DropOut(update, {duration: 0.3}) }}) </script> <h:inputText id="updatefields" immediate="true" onblur="updateTextFields(document.userForm, 'quota', this);" title="Update All Quotas" size="4"/> /** * Gather up form for sending over AJAX. * 1. create hidden field with name of submitted button (to make JSF happy) * 2. find all submit buttons and blank out the names (to prevent * JSF from being confused) * 3. use Form.serialize() to gather values and submit the Ajax request * * For links, might have to add to form to prevent a regular submit: * onsubmit = function() { return false; } * then run onclick(), then run Form.serialize() */
Clearly there was a need for some cleaner solutions that fit more naturally with JSF, rather than hacks that worked around the model. Those same developers were soon flooded with options for mashing Ajax and JSF together (see http://www.jsfmatrix.net/). Some great ideas sprung up, like Ajax4jsf/RichFaces, ICEFaces and ADF Faces/Trinidad. While there were a plethora of solutions, it seemed like everyone was going about it a different way, which led to stovepipes: pick one library and you are stuck with it as the view is likely tied to that Ajax mechanism..
The availability of so many JSF/Ajax frameworks is a good indication that JSF provides a strong foundation for Ajax. But libraries like Ajax4jsf had to wrap the request and mold an Ajax shell around it. Thankfully developers from many of the rich component libraries worked together on the JSF 2.0 expert group and the core Ajax functionality. Now developers can access basic Ajax functionality “out of the box” with JSF 2. The same core will allow component libraries to build from the foundation and create component libraries that can interoperate on the same page.
Now that Ajax is in JSF 2, how do I use it?
Enough history and introductions. This section will jump right to the point and show some examples of the new functionality.
Ajax support in JSF 2 is provided in two primary ways. The first is a JavaScript API: jsf.ajax.request(). This API provides a standard bridge for Ajax requests, and allows for a great deal of fine-grained control. The second is a new tag called <f:ajax>. With this tag you don’t need to worry about JavaScript at all Instead, you can use this tag to add Ajax behavior to your application declaratively.
JavaScript API
Imagine if you could download a library like Prototype and it just understood how to communicate with a JSF component tree. We'll, now you have one. With the new JavaScript API in JSF 2, you call the JavaScript methods directly that will trigger Ajax requests and partial lifecycle processing. This is great when you require JavaScript-level control over the Ajax requests or want to execute your own JavaScript around the request.
Here’s an example of using the JavaScript API to add an Ajax request to a standard command button:
<h:form> <h:outputScript name="jsf.js" library="javax.faces" target="head"/> <h:panelGrid columns=”1”> <h:inputText id="myinput" value="Text: #{userBean.name}"/> <h:outputText id="outtext" value="Echo: #{userBean.name}"/> <h:commandButton id="submit" value="submit" onclick="jsf.ajax.request(this, event, {execute:'myinput',render:'outtext'}); return false;" /> </panelGrid> </h:form>
In this example when the command button is pressed an Ajax request will be sent, triggering partial view processing on the server. The name property of the UserBean will be updated, and only part of the component tree will be rendered in the response. When the request returns, the outtext component will be replaced in the client DOM and the client and server trees will remain in sync.
Let’s break down the important parts from the example above.
The first thing you might notice is the <h:outputScript ...> tag. This is one of a new set of tags in JSF 2 that handle resource loading (JavaScript, CSS, images, etc.). I’m not going to get into this in great detail, other than to say this tag registers the resource jsf.js and tells the JSF implementation to place the script link for it in the html <head> tag. In order to use the JavaScript libraries directly you must include this markup in your page. The jsf.js is a JavaScript file in JSF 2 that contains the standardized JavaScript APIs.
The real meat of this example is the implementation of the command button’s onclick event. This is the actual method call that will trigger Ajax events.
jsf.ajax.request(this, event, execute:'myinput',render:'outtext'});
This method takes 3 parameters; source, event, and options. For a full breakdown of this method please see the online JavaScript API documentation for the jsf.ajax namespace.
• source : The DOM element that triggered the Ajax request, typically this.
• event (optional): The DOM event that triggered this request. This can be used to retrieve additional meta-data about the event, such as whether the shift key was pressed.
• options (optional): This contains a set of name/value pairs from the following table
The two most important options are execute and render. These represent very important concepts in partial view processing support in JSF. Partial view processing is a new mechanism in JSF 2 that allows the JSF lifecycle to be run on one or more component subtrees. For the purposes of Ajax, this processing is split into two steps: execute (decode, validation, update model) and render.
When an Ajax request is sent to the server you rarely want the request to process all of the fields on the page. The execute attribute lets you tell JSF what components should be processed during the request. Only the component(s) identified will go through the validation, conversion, and update model phases. So it’s important to process any components that may impact your request. In our example above we want the myinput component processed on the server.
On the flip-side the render attribute tells JSF what part of the component tree should be rendered and replaced on the client when the response is returned. To the user this is the part of the browser that magically updates without the whole page refreshing. Like execute, you rarely want the entire page to be rendered. In our example, we only want the outtext component to rendered when the request is finished.
While the execute and render targets can be specified using component ids, there are also some new tokens that can be used as shortcuts for these attributes. These can be used for both execute and render instead of a list of component ids.
Let’s put this information to use and modify the previous example. If you are going through the trouble of calling JavaScript for your Ajax requests you might as well get the Ajax to trigger automatically when the user types. Below is the same example as above but without the button:
<h:form> <h:outputScript name="jsf.js" library="javax.faces" target="head"/> <h:panelGrid columns=”1”> <h:inputText id="myinput" value="#{userBean.name}" onkeyup="jsf.ajax.request(this, event, {render: 'outtext'}); return false;"/> <h:outputText id="outtext" value="#{userBean.name}"!/> </panelGrid> </h:form>
So now every time the user enters a character into the input text an Ajax request will be made to the server and when the request returns the outtext component will be rendered. Notice that we do not need to set an “execute” attribute. This is because the default value for execute is @this.
This JavaScript API does double duty. Most of the time, the API will be used by component libraries. But users can choose to use it to trigger Ajax requests of their own, as you have seen. This flexibility means you no longer have to step outside the JSF model to do custom Ajax. For example the ICEFaces library could use this to implement their Direct-to-DOM functionality. The flexibility and desire for component libraries to interoperate provided by this API is key.
I know what you are saying, this is great and all, but I really don’t want to mess with JavaScript. You are not the only one that feels that way. That's why JSF 2 offers a declarative solution out of the box in the form of <f:ajax>, which hides the use of this API.
<f:ajax>
As I hinted above, most users of standard JSF 2.0 will likely use the <f:ajax> tag so that they do not have worry about JavaScript and can still have fine-grain control over their page behavior. Anyone familiar with RichFaces and its <a4j:support> tag will see the obvious correlation in behavior. In fact, the support tag was a big driver and inspiration for the <f:ajax> tag. The RichFaces architect and JSF EG member Alex Smirnov had a large role in defining this tag and how it should work.
Below I’ll show you the same examples as above, but instead of using the JavaScript API we’ll use the <f:ajax> tag. As you will see it is usually much easier to attach Ajax functionality using this tag. First we’ll go over the example with the command button, with a twist.
<h:form> <h:panelGrid columns=”1”> <h:inputText id="myinput" value="Text: #{userBean.name}"/> <h:outputText id="outtext" value="Echo: #{userBean.name}"/> <h:commandButton id="submit" value="submit"> <f:ajax execute=”@form” render=”outtext”/> </h:commandButton> </panelGrid> </h:form>
As you can see this got a lot cleaner, and the <f:ajax> tag is going to take care of all the heavy JavaScript. With this example I used the @form shortcut so that every component in the parent form will be processed on the server. As before we also specify that the outtext should be rendered back to the client. When the button is clicked the request will be fired, and the page updated as before.
In the next example we’ll take the button away and duplicate the second example from the JavaScript API section.
<h:form> <h:panelGrid columns=”1”> <h:inputText id="myinput" value="#{userBean.name}"> <f:ajax event=”keyup” render=”outtext”/> </h:inputText> <h:outputText id="outtext" value="#{userBean.name}"!/> </panelGrid> </h:form>
So what is different here? First we don’t need to set an execute because the default is @this. We are also setting an event attribute for the tag. This is the client-side event of the parent component that the Ajax behavior will bind to and that will trigger the Ajax request. By default input components trigger <f:ajax> when the user changes the value and exits the field, but I wanted a more responsive UI so I choose to use keyup. Also note that you need to remove the on in front of any event you want to use.
The tag has more tricks up its sleeve though. You can wrap an <f:ajax> tag around multiple components and give Ajax behavior to all the children at once. All children will use their default settings and events unless you override them specifically. I’ll demonstrate this using an example from the spec:
<f:ajax> <h:commandButton id=”button1”> <h:commandButton id=”button2”> <f:ajax event=”mouseover”/> </h:commandButton> </f:ajax>
In this example both buttons will have the default Ajax behaviors applied to them. In the case of commandButton this will be when they are clicked. However only the button2 component will also trigger an Ajax on mouseover. This can be useful when your want to apply the same behavior to a group of components without typing <f:ajax> for each tag.
So this is the quick and dirty tour of how to use the new Ajax features in JSF 2.0. The next section is going to go into more details on the partial view processing that makes this all possible.
Great, it’s here! Now how does it work?
In JSF 2, there is now an awareness in the JSF lifecycle of an Ajax request. A big part of this awareness is the PartialViewContext and tree visitor functionality. The PartialViewContext is responsible for capturing the state associated with an Ajax request. This includes what needs to be processed on the server, and what needs to be rendered back to the page. The tree visitor functionality is a new method, visitTree(), on the UIComponent class. The visitTree()method makes it possible to easily traverse a subset of the component tree within the context of the current request.
Once these were in place, the paradigm of a partial page update fit perfectly with JSF because there is a representation on the server of what is rendered on the screen. The page can be updated and JSF kept in the loop. A big part of adding this support involved leveraging the existing event handling mechanism in JSF and extending it all the way to the browser for Ajax based requests.
JSF has always had an "event-based" programming model, but earlier versions had a flaw in that it assumed that every event was to be handled by the server via a traditional POST operation. JSF 2.0 introduced a revamped approach that is fully aware that there are two sides to the equation, that not all events will be processed by the server and that a more efficient method of communication between the client and server can be used (Ajax) rather than a traditional POST. So it's smarter, leaner and even more like GUI frameworks (GUIs that invoke remote services, in fact).
Partial tree processing
When you define an execute value in the examples above you are telling JSF which segments of the server side component tree should run through the JSF request lifecycle or phases. The JSF component tree offers a strong fit for processing an Ajax request like this because components can be uniquely identified. This makes it easy to identify and process a single component or a whole sub-tree.
So when you set an execute parameter like this:
<f:ajax execute=”@form” .../>
Both the client side JavaScript API and the server side lifecycle know that only the components in the parent form should go through validation, conversion, and have there model updated. When actions are called, the values expressed in this way will be there waiting.
Partial page updates
The real magic of Ajax and the noticeable effect that end users ultimately see is that parts of their browser suddenly update without the whole page reloading. JSF 2.0 accomplishes this in a very similar way that RichFaces did in the JSF 1.2 days. Much like the execute attribute, the render attribute tells JSF which segments of the JSF component tree need to be processed (rendered) during the render response phase.
This is actually easier than it may sound because each component node of the tree can be asked to render itself including its children. This means during the render response phase the render attribute is examined. The identified components are found, and asked to render themselves and their children. These are then packaged up and sent back to the client.
Once on the client the JavaScript takes over and finds the corresponding DOM elements, conveniently named the same as their server side twin. The client side code then snips out the DOM elements including their children and replaces them with the new content from the response.
Components playing nice together
Throughout this article I’ve talked about interoperability between component sets. This in the long run will be the real crop of JSF 2.0. The common core of the JavaScript Ajax API is a large aspect of this. If all of the component libraries can agree and use a single core API we’ll go a long way towards true interoperability.
The different component library teams have already started discussions on how to implement, test, and showcase this ability. We are pushing for the different libraries to collaborate on a combined example application. Perhaps we pull a data table from RichFaces, a tree from IceFaces, a menu from ADF, and a collapsing panel from PrimeFaces. This type of application would really do several things. For one it would provide proof and an example to developers that JSF 2.0 component libraries really can work together. For another it will help us all to shake out the lumps and issues developers will run into with the specification.
This second point should not be underestimated and here is why. The items found this way represent areas of implementation that could cause component libraries to not function together, or point out areas in the spec that need more definition. What this means to the JSF developer is that the component libraries will be taking a lot of the risk out of JSF development for you. When this work is completed, and the various projects release their JSF 2.0 integrated component sets JSF developers will have one of the largest and most advanced component libraries available in web development.
Wrap Up
If you think all of this is neat, wait until you hear about the behavior framework that the <f:ajax> tag is built on. There is an underlying concept at work here that manifests itself in JSF 2.0 as a new concept of component behaviors. The interesting thing about behaviors is that they generalize the process by which functionality, both server-side and client-side , can be attached to components, and not just Ajax-related functionality. Once a component is capable of having a behavior attached to it, the door is open for having all sorts of new behaviors attached as well. The next article in this series will review the behavior framework in detail. Including how to create your own behavior, and some possible use-cases for this.
This behavior framework is an example of one of the extension points that have been baked into the JSF 2.0 specification. Its predecessor, JSF 1.2, also allowed frameworks like Facelets, Seam, and RichFaces to extend and improve functionality. Being able to support extensions is critical for the success of any technology. It allows for improvements from its users as technology and requirements change - as they always do, and JSF 2 is well positioned to support this growth.
Opinions expressed by DZone contributors are their own.
Trending
-
Extending Java APIs: Add Missing Features Without the Hassle
-
Auditing Tools for Kubernetes
-
The SPACE Framework for Developer Productivity
-
Effortlessly Streamlining Test-Driven Development and CI Testing for Kafka Developers
Comments