Monday, January 23, 2012

AJAX

Ajax allows us to give the web application a rich interface.  We do not have to process the entire page, nor submit the entire page as we interact.  With JSF and Ajax, we can implement most, if not all, the features we would see in a desktop Swing application.  Even better, we can do all this without installing any additional software on the client.  We need no registry entries, no installation program, etc.  We can run from any where, on many different platforms the same application with the same rich interafce.  All we need is a capable web browser.  Although we are just now beginning the Ajax discussion in this tutorial, the examples of Ajax are throughout the code.  Primefaces, by default, enables Ajax.  The toolbar, menu, validation, dialog boxes all make use of Ajax.  JSF without Ajax is like a web page without style sheets.  Ajax is so integrated, we even have to turn it off in a couple spots for either redirection, or demonstration of code or concept.  The following is by no means exhaustive of all the Ajax we are using in the code.

To illustrate the use of Ajax, I made a special dialog box just to demonstrate it.  It has no Primefaces included (with the exception that the dialog box is a Primefaces component).  We have already seen the code in relation to validation.  Since I have already posted the code, I will just refer you to the previous (Validation) post for the full text.


Here we have a dialog box that has its own form, input fields, output fields, validations, messages, and several buttons.

The first example of Ajax on the page is the input text component "newdemoother":
     <h:inputText value="#{orderBean.otherName}" id="newdemoother" >
              <f:validator validatorId="com.testit.NameValidator"/>
              <f:ajax event="blur" render="msgmsg" onevent="ajaxSample"/>
    </h:inputText>

When the focus is lost, as indicated by the attribute event="blur" we call the JavaScript method ajaxSample.  An Ajax component can be invoked off the DOM events supported by the component plus "action" for action components or "valueChange" for editable components.  So, since an inputText component renders to <input>, the DOM events are:
    onblur, onchange, onclick, ondblclick, onfocus, onmousedown, onmousemove, onmouseout, onmouseover, onmouseup, onkeydown, onkeypress, onkeyup, onselect

We call ajaxSample as defined in our jsfunctions.js

function ajaxSample(data) {
    s = "ajaxSample 1\n";
    s += data.toString() + "\n----------\n";
    if(!(data instanceof String)) {
        s += data.source.id +"\n";
        s += data.status + "\n";
        s += data.type + "\n";
        s += data.responseText + "\n";
    }
    alert( s );
    return true;
}

Notice that the JavaScript function is called with an event object.  This event object holds the status, component id, etc.  We can use this to perform whatever is necessary.  In our sample function it displays parts of the event.  When we input data into the component "newdemoother" and then change the focus, this method is called.  But it is actually called, three times.  Each time, the status is changed.  The three statuses are begin, complete, and success.


Analyzing the alert the method displays, we see the data passed in as the event.  The component id is: demoForm:newdemoother (obviously we didn't use prependId="false").  The status is complete.  The type is event.  The response text is in xml and includes the updating of the msgmsg component. etc. etc.  After the Ajax request completes, it will re-render the components listed in the render attribute.  In this particular case, that is the msgmsg component which displays the validation message returned from the NameValidator.

When we review the buttons, we can see the consequences of using / not using Ajax.  First, we have a client side button, which does not make any requests of the server.  There would be no reason to implement Ajax since this is entirely client side.  Ajax stands for Asynchronous JavaScript and XML.  The Asynchronous means asynchronous communication for passing data to and from the server.  This button is of type button.

The rest of the buttons are of type submit, which will make requests of the server.  The first two lines do not have Ajax, and the last two do so we can compare what happens.  

The first column is an event action - specifically onclick.  The first button does not call any validation and uses the immediate attribute.  When this is clicked, an alert is displayed, when we close the alert, the dialog box disappears.  When we re-display the dialog box, the validation messages are gone.  What happened?  When the page was rendered, orderBean.sendAlert was rendered as showMessage('Executed a bean that returned a JavaScript Command').  When this button was clicked, the showMessage javascript method was called which popped up an alert.  When this method returned, the page was refreshed.  When it was refreshed, the dialog box disappeared and the messages were reset to null.  When we re-display the dialog box, it has already been rendered without the messages.  Note: the button was rendered to showMessage at the time of the page rendering.  It does NOT call the server as the button is clicked, but calls what the button had rendered to.

The second event button acts very similarly to the first, but when the dialog box is re-displayed, the validation messages are displayed.  Why?  Well the page has been rendered to call the javascript method which it does, when it returns it submits the form which validates its fields.  The fields call their validators and return their messages.  The validators failed so the values are not posted to the model, and the application is not envoked, but this component has no invocation of an app method.  Then the page is refreshed and everything rendered.  This has the effect of closing the dialog box, although it isn't really closed as much as it isn't displayed.  Notice the page flicker as the page is re-displayed.

The third event button implements Ajax but is otherwise the same as the first event button.  When we click the button, the alert pops up and the validation messages are removed, but the dialog box is still displayed.  Why?  Well, we told it to update the entire form, but not the entire page.  So the fact the dialog box was being displayed means it stays being displayed.  No validation occurred, so no messages were retrieved, so they disappear.

The forth button acts a bit differently.  It only displays the validation message for the first text box.  Why?  We told it render="newdemomsg" which means only that component, or the components listed (because you can put multiple components separated by ; in the render string) will be updated.  Of course, the alert was still displayed.

The second column is an action call.  Now, in order to stay on the same page, we return a null so we can see the effects of the Ajax.  The first 2 buttons again have the effect of closing the dialog box with the second validating the input values.  The last two have the effect of leaving the dialog box open with the second validating the input values.  If we were to return say index, the first and third would navigate to the index.xhtml page.  The 2nd and fourth would only navigate if the validation passed.  Remember validation short circuits the JSF lifecycle such that if validation fails, you will not post the values to the model, nor will you execute the application.

The third column will execute an ActionListener.  The first and third button will do so immediately, and the second and fourth will only do so if validation works.  Notice, that means the message will not change if validation fails since the message is changed in the bean method.  Also, the first two buttons again behave like the others in that the page is refreshed, but the dialog box is set to hidden - which has the effect of hiding the dialog box.

The forth column is "special" in that it demonstrates the calling of an event, an action, and an ActionListener all  in the same button.  So, what wins?  Well, the action listener is called first, so the assignment of the message will be overwritten by the assignment in the action method.  The event is called before the render so the alert shows up, then the page navigates if the validation works, or is skipped (i.e. immediate=true).  Also remember, even though the application is not called if validation fails, the bean will be rendered for the event button.  So, if you assign something in the event button via a bean, it will be assigned whether or not validation succeeds.

Although we didn't demonstrate it, we could also have put in a client side call for onerror.  i.e. <f:ajax execute="@form" render="@form" onerror="somejavascript" />


Given these, we can call a bean, navigate, execute a script, etc. etc.  We just have to chose the correct combination.  Remember also, if we call an event, it will be called multiple times, so it is a good idea to check for the status of the Ajax event.  Refer to http://jcp.org/aboutJava/communityprocess/final/jsr314/index.html for a complete description of Ajax.

1 comment: