The AjaxComponent strategy for JSF: The best of both worlds

Ajax-enable your components with a phase listener

1 2 3 4 5 6 7 Page 4
Page 4 of 7

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 encode() method. First you get and save the server URL. Next, you grab the <div> element to use for outputting messages. In that case, you actually save the domNode of the <div>. Then you get and save the clientId. Finally, you get the button element, and attach an event listener to it.

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 cleintId (which is always unique for every component on the page) into the IDs of the elements you need to get.

Using 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.)

So now you've gotten to the point where the user has clicked on the button. When that happens, the JavaScript executes the 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
    });
}

Here again you leverage dojo to make the Ajax call painless. First, you get the <input> element that contains the text entered by the user, and hold onto its value in the inputField variable.

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 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.

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 dojo.io.bind() call, which has an associative array for its argument.

  • The 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.
1 2 3 4 5 6 7 Page 4
Page 4 of 7