JSF Central - Trinidad in Action Part 2
JSF Central

 
 Home 
 
 Products 
 
 Articles & Books 
 
 Resources 
Trinidad in Action
 
Trinidad in Action Part 2
by Matthias Wessendorf
29 Mar 2010 01:00 EDT

In the second installment of the Trinidad series, Matthias Wessendorf shows how Ajax is built into all the Trinidad components. You will also learn how easy it is to use the client- and server-side Ajax API, which gives you a straightforward way to add application-specific Ajax support.


In the first article of the Trinidad series, we saw that Trinidad makes it fairly easy to integrate Ajax into your application using the Trinidad components. However, there will be times when this is not always enough. Trinidad also provides an extensible client-side and server-side Ajax API, which you will find very useful in supporting your Ajax use case realization.

Ajax components

All Trinidad components are Ajax-enabled, which means you get Ajax functionality almost for free. The components support Ajax with three different attributes: partialSubmit, autoSubmit, and partialTriggers (see the first article in this series to learn more about that). Not only is Ajax supported by the components, it is actually a built-in feature! Take the Trinidad <tr:tree> for instance. Composing a tree (figure 1) with Trinidad is fairly easy, as you see here:

  Figure 1. Trinidad tree control
Figure 1. Trinidad tree control

<tr:tree var="entry" value="#{bean.dataModel}"> <f:facet name="nodeStamp"> <tr:panelGroupLayout> <tr:outputText value="#{entry....}"/> ... </tr:panelGroupLayout> </f:facet> </tr:tree>

Note that when you open or close a node on the tree, Ajax handles the operation for you. The same is true for the <tr:table> component, where you can scroll through a pretty large data set. Again, Ajax handles the navigation and you, as a page author, don’t need to treat scrolling as a special case.

However, the Ajax support in Trinidad components, which is mainly implemented by using partialTriggers to refer to a particular Ajax source, cannot be used in all cases. Let’s look at some cases where the Ajax API can help.

Server-side Ajax API

Trinidad’s server-side Ajax API gives you a good amount of flexibility when working with Ajax. Several use cases can be implemented with it, like sending JavaScript content to the client or writing custom components.

Updating components programmatically

Sometimes you cannot update components with the Ajax postback. Some of these scenarios are more common than it may seem at first:

  • You may need to update a non-Trinidad component that doesn’t have partialTriggers available.
  • You may need to update a component only when a certain condition occurs.
  • You may not know which component needs to be updated until you process on the server.

For these cases (and any others you come up with), you can always programmatically update a JSF component, by using RequestContext.addPartialTarget(). All you need to do is add the following code in your Facelet:

<tr:commandButton text="refresh" partialSubmit="true" action="#{create.updatePage}" /> <h:outputText id="status" value="some value..." />

Then in the updatePage() method, you simply do the following to update the standard <h:outputText> component:

public String updatePage() { FacesContext ctx = FacesContext.getCurrentInstance(); UIComponent comp = ctx.getViewRoot().findComponent("status"); ((ValueHolder) comp).setValue("updated by Java-API"); RequestContext rc = RequestContext.getCurrentInstance(); rc.addPartialTarget(comp); ... }

After the Ajax postback, caused by the <tr:commandButton>, the Trinidad client-side Ajax engine will update the rendered markup of the <h:outputText> component.

Creating custom components

Not only can you use the Ajax facility in Trinidad with existing components, such as Tomahawk or the standard components, you can also implement your own custom JSF components and add the Ajax feature by leveraging the Trinidad API. If you're implementing a custom component -- when you aren't extending the Trinidad UIXComponentBase base class or one of its subclasses -- and you want to support partialTriggers, you'll need to use addPartialTriggerListeners() from RequestContext inside the component’s decode() method. If you deliver events, and you want a component to be the target of partialTriggers, you'll need to use partialUpdateNotify() inside the broadcast() method of your component. You can find out more about partial page rendering here.

Calling JavaScript from the server

Another cool feature of the Trinidad Ajax API is the ExtendedRenderKitService interface. It allows you to “call” JavaScript from the server, or at least it looks like it does. Imagine a case in which you need the Dojo Dialog to show a status, after a server-side action. The ExtendedRenderKitService allows you to add JavaScript that is executed by the browser after your HTTP request is submitted. Therefore it may look like you are calling JavaScript from the server. The usage of this API is straightforward: public String doStuff() { ... FacesContext context = FacesContext.getCurrentInstance(); ExtendedRenderKitService erks = Service.getRenderKitService(context, ExtendedRenderKitService.class); erks.addScript(context, "hello('" + some parameters + "');"); return null; }

The addScript() method take two arguments: the FacesContext and a String that represents the JavaScript call. The added JavaScript shows up at the very end of the response, like <script ...>hello(‘some params’);</script>. In the above example the hello() function will be executed once the response has been processed by the browser. Inside this hello() function you could call some third party JavaScript libraries such as Dojo or jQuery. Another option is to generate JavaScript functions on the server and send them down.

Client-side Ajax API

Trinidad’s Ajax API is not limited to the server. The library also offers a set of functions you can use on the client-side, such as submitting or monitoring Ajax requests.

Sending an Ajax request with the JavaScript APIs

If you're writing a custom component, you may want to be able to send an Ajax request from the client. Or, as a page author, you may want to add custom Ajax behavior. The Trinidad library offers some functions for doing this:

var page = TrPage.getInstance(); page.sendPartialFormPost( theFormElement, {param1: "value1", param2: "value2"}, {header1: "headerValue1", header2: "headerValue2"});

This will automatically gather up all fields for the form theFormElement and include their values with the postback as well as two additional parameters. The headers are completely optional, and can be omitted. The parameters are also optional, but usually you'll want at least one. If the content of the form happens to include a non-empty file upload component (input type="file"), the request will automatically switch to an alternative IFRAME-based method that supports file upload, without any change in your code on the server or client. The Ajax postback, submitted by the sendPartialFormPost(), is going through the complete JSF lifecycle. There is no PhaseListener or separate AjaxServlet for this in Trinidad.

If you wish to send an Ajax request on your own, without going through the JSF lifecycle, use the RequestQueue object off of the TrPage JavaScript object:

var queue = TrPage.getInstance().getRequestQueue(); queue.sendRequest(this, this.myAjaxCallback, "http://localhost:9090/jsonDataServlet?foo=bar");

The callback (myAjaxCallback) will be called with an instance of TrXMLRequestEvent, which supports the following methods:

      
  • getStatus(): returns one of TrXMLRequestEvent.STATUS_QUEUED, .STATUS_SEND_BEFORE, .STATUS_SEND_AFTER, and .STATUS_COMPLETE
  •  
  • getResponseXML(): returns the XML document
  • getResponseText(): returns the text of the reply
  •  
  • getResponseStatusCode(): returns the HTTP status code
  • getResponseHeader(): returns an HTTP header
  •  
  • getResponseContentType(): returns the content type of the response
  •  

You can implement the callback like this:

function myCallback(event) { if(event.getStatus() == TrXMLRequestEvent.STATUS_COMPLETE) { var jsonData = event.getResponseText(); // do some updates in the DOM } }

This callback will update the DOM when the Ajax request has been completed.

Monitoring Ajax requests

Trinidad comes with a component, <tr:statusIndicator>, that monitors an Ajax request for you. By default the component renders a little moving wheel icon when the request is being processed (see figure 2).

  Figure 2. The Ajax request monitor icon
Figure 2. The Ajax request monitor icon

It is also possible to show different content, if needed. The component uses two facets for this:

<tr:statusIndicator> <f:facet name="busy"> <tr:outputText value="Loading..."/> </f:facet> <f:facet name="ready"> <tr:outputText value="Done!"/> </f:facet> </tr:statusIndicator>

The Trinidad library also has an API which allows you to create custom code for doing the request monitoring. A pretty common example is to display an HTML <div> element when the Ajax request is active, and hide it when the request has been processed. For this, you need to register a custom callback on the Trinidad RequestQueue object:

var requestQueue = TrPage.getInstance().getRequestQueue(); requestQueue.addStateChangeListener(myCallback); function myCallback(state) { var busy = state == TrRequestQueue.STATE_BUSY; var div = document.getElementById("load"); div.style.display = busy ? "inline" : "none"; }

Your callback will be passed a single parameter, which will be either TrRequestQueue.STATE_READY or TrRequestQueue.STATE_BUSY, depending on the current state of the request queue. The statusIndicator component uses this same mechanism to know when to start and stop spinning its indicator.

DOM update events

If you add a "DOM replace listener" on the TrPage object, Trinidad notifies you when an Ajax response to the client indicates that the DOM has been replaced:

function domCallback(oldDom, newDom) { ... } TrPage.getInstance().addDomReplaceListener(domCallback);

The callback is called with two parameters: the old DOM element and the new DOM element that is replacing it. This callback is invoked after the replacement has happened.

Conclusion

The Trinidad library has a lot of facilities to do Ajax. All components have Ajax integration, and the library offers a solid set of client-side and server-side methods to integrate Ajax into your application. With Trinidad it is fairly easy to integrate other third party JavaScript libraries as well. The Ajax API itself is straightforward and offers you, as an application developer, a powerful and flexible tool.

Resources



RSS feed(all feeds)

The Editor's Desk
Podcasts
Inside Facelets
In the Trenches

Site version 1.83  Report web site problems

Copyright (C) 2003-2015 Virtua, Inc. All Rights Reserved. Java, JavaServer Faces, and all Java-based marks are trademarks or registered trademarks of Oracle Corporation. in the United States and other countries. Virtua, Inc. is independent of Oracle Corporation. All other trademarks are the sole property of their respective owners.