Wicket 1.1 has basic, yet highly experimental support for AJAX. Pending our AJAX efforts scheduled for Wicket 1.2, I wanted to show how this AJAX thingy might work using Wicket. Nothing fancy dandy, but something I can use directly in my current project.

NOTA BENE

  • this is my first AJAX experiment, so this is definetely not a best practise
  • AJAX support is in its infancy in Wicket 1.1, so this may not work in future versions
  • Wicket 1.1 is still BETA software. Stuff may break
  • I used stuff that is currently only in HEAD (updateModel change), so this won't work with a vanilla wicket-1.1-b1

That said, let's continue with my AJAX experiment!

My current project will be something like a webbased spreadsheet, so I see a lot of AJAX stuff happening in the future with this project (if that darn manager would only let me): calculations done on the serverside would be done 'instantaneously'. The results of the calculations would be sent directly to the client, without having to submit anything. Needless to say, I'm pretty enthousiastic on putting AJAX into good use here.

To start slowly I want to update the data on the serverside of a text field on a form without doing a full blown post. Eelco pointed me to the Form input example, where on the integer field an AJAX call is performed (NOTE the demo currenlty only works with internet explorer, this has already been fixed!). This call only calls the validation on the field itself, but this is nearly enough functionality for me to begin with:

  • send modified field data to server
  • validate value
  • when data is valid, update the model
  • send status back to client (error or success)
  • update class of field to show status

So when I take this code, I should be almost finished. The example uses the dojo toolkit for the AJAX request handling, so this is what I'm using.

The markup for the page I'm creating is very simple:





<input wicket:id="field" type="text />

And the corresponding Java code is also simple:

public class MyPage extends WebPage {
    public class FormObject implements Serializable {
        private String field;
        public String getField() { return field; }
        public void setField(String value) { field = value; }
    }

    public MyPage() {
        Form myForm = new Form("form", 
                new CompoundPropertyModel(new FormObject()), null) {
            protected void onSubmit() {
            }
        };
        TextField field = new RequiredTextField("field");
        myForm.add(field);
    }
}

And a properties file for the RequiredValidator (required textfield automatically adds the validator to the textfield):

form.field.RequiredValidator=${name} is required.

This is basically a very simple input form. No special stuff happening here. On with the AJAX stuff!

Now, when the AJAX event has been executed on the server and a response is returned, I want the classname of the inputfield set to one of the two defined CSS classes: success or error. The dojo kit supplies us with a bind method which does the call to the server and takes a handler for when the answer is returned:

dojo.io.bind({
    url: "http://foo.bar.com/sampleData.txt",
    load: function(type, data, evt){ /*do something w/ the data */ },
    mimetype: "text/plain"
});

(shamelessly taken from the dojo site). I need to change the 'function' part here: the string /*do something w/ the data*/ will have to become something like:

field.className = data;

The next thing to do is add a listener for the AJAX request to the field. Wicket provides the daring with DojoEventRequestHandler giving me out-of-the-box Dojo support. But I take a short cut. Eelco already has a ValidationEventRequestHandler, so I just copy that sourcecode and modify the bits I need:

protected final IResourceStream getResponse() {
    StringBufferResourceStream s = new StringBufferResourceStream();

    formComponent.validate();
    if (formComponent.isValid()) {
        formComponent.updateModel();
    }
    s.append(formComponent.isValid() ? "success" : "error");

    return s;
}

This performs the actual AJAX action on the server. I validate the incoming value, and when valid, I update the model on the form component. Lastly I return either 'success' or 'error' to the browser.
For the JavaScript side, we need to add an onchange handler which calls the dojo functionality. The update function that is called from here will be added to the header of the page (this uses
the new Wicket JavaScript support!):

;

Here you see that we call the dojo.io.bind function, and provide it with our own functionality to set the class of the field. When we add this to the header from within the Wicket code it looks like this:

public final void doPrintHead(HtmlHeaderContainer container) {
    String s =

    "\t<script language=\"JavaScript\" type=\"text/javascript\">\n"
            + "\tfunction update(componentUrl, componentPath, field) { \n"
            + "\t\tdojo.io.bind({\n"
            + "\t\t\turl: componentUrl + '&' + componentPath + '=' + field.value,\n"
            + "\t\t\tmimetype: \"text/plain\",\n"
            + "\t\t\tload: function(type, data, evt) {\n"
            + "\t\t\t\tfield.className = data;\n" + "\t\t\t}\n"
            + "\t\t});\n" + "\t}\n" + "\t\n";

    container.getResponse().write(s);
}

This looks complex, but it is just escaped JavaScript (the same as above). As a final thing to do, we need to change the onchange event handler on the field so that it calls the update JavaScript function.

public final void onComponentTag(final Component component, final ComponentTag tag) {
    final ValueMap attributes = tag.getAttributes();
    final String url = formComponent.urlFor(IEventRequestListener.class) 
        + "&id=" + getId();
    final String attributeValue = "javascript:update('" 
        + url + "', '" + formComponent.getPath() + "', this);";
    attributes.put(getEventName(), attributeValue);
}

Put in the rest of the functions that are already provided for by Eelco, and we have a working Ajax enabled field.

The accomplishment is not huge on a global scale, but I find it very cool to have done this basic stuff. Now before
you start doing this yourself
: this is experimental code, and is not the official AJAX support of Wicket. There are
no guarantees that this will work in any version of Wicket now or in the future.

Technorati Tags:
,
,
,