Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Sunday, February 5, 2012

Taking The New Wicket Plugin For Netbeans For A Test Ride

I was very, very pleased and happy to read Geertjan's blog entry announcing his updated and shall I dare say modern (my words, of course) Wicket Plugin for Netbeans v7.1. Previous versions of the Wicket Plugin were tied to the Wicket libraries that were included within the plugin's nbm files. Whenever you created a new Wicket project the plugin would contribute those jars to the new project. If you wanted your project to use a different version of those jars you had to remove the Wicket jars from your project and then add the version of the jars that you preferred. Not that this was a big deal, mind you, but it just seemed, to me at least, that this was an unnecessary built-in dependency.

In this release Geertjan has removed all such dependencies while also improving the plugin's synergy with Netbeans Library Manager. Netbeans allows you to create your own libraries using its Library Manager. The libraries you create are nothing more than named collections of 1 or more jars that when selected are added to your project's class path. When creating a new project the new Wicket plugin will list all libraries that you have created using the Library Manager whose names start with 'wicket'. If you create your own library for Wicket v1.5.3 for example and name it Wicket-1.5.3 then when you create a new Wicket project the plugin will find it and offer it as an option in the Version list of libraries. If you select it from the list the jar files associated with the library will be included in your new project.


In the above snapshot you can see that in the Version list on the Frameworks page the libraries whose names all start with wicket (case insensitive) are listed as options.

While I have always believed that the Wicket plugin propelled Netbeans to the height of being the preeminent IDE for Wicket development, I am further convinced of that by the release of this latest version of the Wicket Plugin. Great job, Geertjan and might I be so presumptuous as to offer you much thanks, not just from myself but from the Wicket developer community in general, for your continued effort and dedication. Marvelous!

Sunday, December 25, 2011

Merry Christmas And A Happy New Year Message... The Wicket Way

add(new Label("label","Wishing You All A Very Merry Christmas And A Happy New Year!"));

Wednesday, December 21, 2011

A Reusable jQuery UI Autocomplete Wicket Component

* One in a series of articles on Wicket Interfaces & Methods To Master *

In my previous article I demonstrated using Wicket's AbstractAjaxBehavior to integrate with the jQuery UI Autocomplete component. In this article I build upon those concepts to create a reusable JQueryAutocompleteTextField. If you haven't read my previous article please do so now. Also, this article assumes you know how to add libraries (jars, libraries, projects) to a project using Netbeans.

Note: you may check out read-only working copies of the source for this article anonymously over HTTP:

  • The wicket/jQuery integration library svn checkout - http://wicket-jquery-integration.googlecode.com/svn/trunk/ wicket-jquery-integration-read-only
  • The demo application svn checkout - http://wicket-jquery-integration-demo-app.googlecode.com/svn/trunk/ wicket-jquery-integration-demo-app-read-only

Wicket provides numerous reusable components and behaviors that makes page composition simple. Any custom components that we develop should be just as easy to use and be as reusable across projects as well. These factors serve as motivation for encapsulating all the logic I presented in the previous article into a fully self contained reusable component hosted in its own jar file which can be reused in any project just like any one of Wicket's standard components. 

I will be using Netbeans v7.0.1 throughout this article. If you aren't using Netbeans along with the Wicket Plugin for your Wicket development then you aren't using the best IDE available for Wicket development period. This powerful duo provides a level of support for Wicket development that no other IDE can offer. I highly recommend that if you haven't done so already to please download and install Netbeans and then install the Wicket Plugin. You won't regret it, I promise you.

This article will be a little more in depth than my previous ones. So go make yourself a pot of coffee and then lets roll up our sleeves and get on with it then...

Objectives And Requirements

First off, any project worth your effort and time is worth at least minimaly defining its objectives and requirements. Otherwise, how would you know if you are successful or not? So, before we get into the nuts and bolts of the implementation, let us minimally identify the objectives and requirements of the JQueryAutocompleteTextField component:
  1. JQueryAutocompleteTextField must fully encapsulate any resources it requires. In the case of our component, the resource is the Javascript code needed for implementation on the client. Therefore the Javascript should be a packaged resource and adapted and rendered along with the markup for the JQueryAutocompleteTextField. User's shouldn't have to write jQuery script to use JQueryAutocompleteTextField.
  2. JQueryAutocompleteTextField should be just as simple to create as it is to create an out-of-the-box TextField. It also has to be as generic as an out-of-the-box TextField. In the case of JQueryAutocompleteTextField we will extend Wicket's TextField and add our own generic implementation onto that.
  3. JQueryAutocompleteTextField has to be reusable across projects so that means it has to be hosted in its own jar file.
With our requirements and objectives now having been stated, lets move onto the project structure we will need in order to create a reusable Wicket component library.

Create A Library Project

As I previously stated above in Objectives And Requirements, item #3, the JQueryAutocompleteTextField needs to be hosted in its own jar file. Our goal here is to provide a reusable library. Users of this library will have to include it in their classpath in order to compile their own code and they will also need to have the Wicket jar files on their classpath so that the library can resolve its dependencies on Wicket as well.
  1. Fire up Netbeans and from the main menu select File | New Project | Java | Java Application and click Next.
  2. Enter any name you want for the Project Name. I am using WicketJQueryIntegration. If the Use Dedicated Folder for Storing Libraries option is selected, unselect it. Also unselect Create Main Class if it is selected and then click Finish for Netbeans to generate the project.
  3. Right click on the default src package and select Refactor | Rename and enter any package name you wish to use. I am using com.wicket.jquery.integration.autocomplete.
You should now have a project structure that looks this:







The next thing to do is to add Wicket 1.5 to our project. If you don't already have Wicket you can go to http://wicket.apache.org/ and download it. I am using version 1.5.3.

WicketJQueryIntegration also requires google-gson which you can download if you don't already have it. Add it to the project as well.

With our dependencies added to the project and accounted for we need to do one more thing and that is to insure that the libraries we require for compilation aren't packaged in the jar - it is the responsibility of the users of JQueryAutocompleteTextField to provide the dependencies on these in their classpath. If we don't do this, then we are building in a level of dependency on the exact same versions of these libraries and we don't want to do that.

Right click on the project node and select Properties and select Packaging. Uncheck the Copy Dependent Libraries option and click OK.











We now have a project suitable for creating a reusable library that doesn't impose dependencies upon its users and our project structure now looks like this:























Implementing JQueryAutocompleteTextField

We will begin implementation by creating a subclass of AbstractAjaxBehavior. In my previous article we used an implementation of AbstractAjaxBehavior that was tightly coupled to providing support for selecting states. However, because our goal is to create a reusable implementation, one that isn't tightly coupled to any particular use case, our implementation must therefore provide flexibility, allowing the user to implement their own requirements.

Create a Java class in the com.wicket.jquery.integration.autocomplete package. I named mine AbstractJQueryAutocompleAjaxBehavior. In the editor mark the class as abstract and extend the class from AbstractAjaxBehavior.

The constructor needs to take one parameter, a string whose value is a jQuery selector that identifies the target html text field element that will be used to host the jQuery UI Autocomplete component. Our class also needs a field to store this value:


public abstract class AbstractJQueryAutocompleAjaxBehavior extends AbstractAjaxBehavior {

    // The jQuery selector to be used by the jQuery ready handler that registers the autocomplete behavior
    final private String jQuerySelector;

    /**
     * Constructor
     * @param jQuerySelector - a string containing the jQuery selector
     * for the target html element (<input type='text'... of the jQuery UI
     * Autocomplete component
     */
    public AbstractJQueryAutocompleAjaxBehavior(String jQuerySelector) {
        super();
        this.jQuerySelector = jQuerySelector;
    }


As was stated in our Objective And Requirements, item #1, we don't want the users of our component to have to write their own jQuery code to wire up jQuery UI's Autocomplete component and therefore our component must render that code to the client page. Here's the boilerplate javascript that we want to use to render to the client page:

$(document).ready(function(){
    $('${selector}').autocomplete({
        source: function(req, add){
            //pass request to server  
            $.ajax({
                url: '${callbackUrl}',
                type: 'GET',
                cache: false,
                data: req,
                dataType: 'json',
                success: function(json){
                    var suggestions = [];  

                    //process response  
                    $.each(json, function(i, val){  
                        suggestions.push(val.name);  
                    });
                        
                    // call autocomplet callback method with results
                    add(suggestions);
                },
                error: function(XMLHttpRequest, textStatus, errorThrown){
                    //alert('error - ' + textStatus);
                    console.log('error', textStatus, errorThrown);
                }
            });            
        }
    });
});


Create a new Javascript file in the com.wicket.jquery.integration.autocomplete package and name it autocomplete.js. Then copy the code above into it and save the file.

We are faced with a slight dilemma because we have no way of knowing which html element the user is going to use. The solution, as implemented, is to allow the user to tell us that by providing a jQuery selector in the constructor that identifies it. But wait, how can we alter the Javascript to use this selector? Well, fortunately for us Wicket makes this kind of easy. Wicket supports modifying packaged resources through a process known as interpolation which just means replacing one thing in the resource with another thing. In Wicket's case the things that need to be replaced are identified by ${...} markers. In each marker we provide a name for the marker. In the above Javascript file we provide for two markers, ${selector} which will be replaced with the jQuery selector provided in the constructor and ${callbackUrl} which will be replaced by the callback url to our Wicket Ajax event handler which we will later implement by overriding onRequest.

When we interpolate we provide a HasMap that contains key/value objects. Their keys must match the names we gave each marker and their associated values are what will be used to replace the marker with. When our Javascript resource is contributed to the page it will therefore be rendered with both the jQuery selector and the callback URL. Let's implement that now by overriding the renderHead method of AbstractAjaxBehavior:

    /**
     * Contributes a jQuery ready handler that registers autocomplete
     * behavior for the html element represented by the selector.
     * 
     * The generation of the ready handler uses interpolation, applying
     * the jQuery selector and the variable name of the return call
     * back url.
     * 
     * @param component
     * @param response 
     */
    @Override
    public void renderHead(Component component, IHeaderResponse response) {
        super.renderHead(component, response);

        Map<String, CharSequence> map = new HashMap<String, CharSequence>(2);
        map.put("selector", jQuerySelector);
        map.put("callbackUrl", getCallbackUrl());
        PackageTextTemplate packageTextTemplate = new PackageTextTemplate(getClass(), "autocomplete.js", "text/javascript");
        String resource = packageTextTemplate.asString(map);
        response.renderJavaScript(resource, jQuerySelector);
    }

In the code above we create a HashMap and add the jQuery selector and callback url to it, the names of which as you can see match those we used in our markers. Additionally, we obtain a PackageTextTemplate resource for the autocomplete.js file which resides in the same package as this class and then we call its asString method passing it the HashMap. asString will interpolate our resource using the HashMap we provided and return the interpolated content of the resource as a String. That solves our slight dilemma quite nicely I think and with very little code.

Finally we need to actually render the resource to the client page. This is done by calling renderJavaScript, passing it the interpolated resource and the jQuerySelector parameter as a unique id.

Besides rendering the Javascript we must also handle the actual Ajax callback by overriding the onRequest method. Remember, when we stated our objective and requirements we said in item #2 that the component has to be generic. All that means is that we won't assume how the user intends to use the component. Here is the code for our generic implementation of onRequest :

    @Override
    public void onRequest() {
        Logger logger = LoggerFactory.getLogger(this.getClass());
        logger.info("ajax request received");

        RequestCycle requestCycle = RequestCycle.get();
        Request request = requestCycle.getRequest();
        IRequestParameters irp = request.getRequestParameters();
        StringValue term = irp.getParameterValue("term");
        List<?> matches = getMatches(term.toString());
        String json = convertListToJson(matches);
        requestCycle.scheduleRequestHandlerAfterCurrent(new TextRequestHandler("application/json", "UTF-8", json));
    }


In the code above we retrieve the parameter passed to the callback which is the term the user entered into the TextField tied to the jQuery Ui Autocomplete component. We use that term by passing it to an abstract method which we define as follows:

public abstract List<?> getMatches(String term);

Because we declared this method as abstract it will have to be implemented by the user of AbstractJQueryAutocompleAjaxBehavior which I will get to shortly but this is one way we keep this generic, by deferring implementation of this method. We also keep this generic by defining this method's return value using generics and in our case as  a List of some object.

Finally, onRequest then calls convertListToJson, a method that converts the List of objects returned from the getMatches method to a Javascript array of JSON objects. That array is then returned to the client which will be passed to the success callback method of the Autocomplete component defined in our Javascript.

Here's the complete code for AbstractJQueryAutocompleAjaxBehavior:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.wicket.jquery.integration.autocomplete;

import com.google.gson.Gson;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.request.IRequestParameters;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.handler.TextRequestHandler;
import org.apache.wicket.util.string.StringValue;
import org.apache.wicket.util.template.PackageTextTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author jeffrey
 */
public abstract class AbstractJQueryAutocompleAjaxBehavior extends AbstractAjaxBehavior {

    // The jQuery selector to be used by the jQuery ready handler that registers the autocomplete behavior
    final private String jQuerySelector;

    /**
     * Constructor
     * @param jQuerySelector - a string containing the jQuery selector
     * for the target html element (<input type='text'... of the jQuery UI
     * Autocomplete component
     */
    public AbstractJQueryAutocompleAjaxBehavior(String jQuerySelector) {
        super();
        this.jQuerySelector = jQuerySelector;
    }

    /**
     * Contributes a jQuery ready handler that registers autocomplete
     * behavior for the html element represented by the selector.
     * 
     * The generation of the ready handler uses interpolation, applying
     * the jQuery selector and the variable name of the return call
     * back url.
     * 
     * @param component
     * @param response 
     */
    @Override
    public void renderHead(Component component, IHeaderResponse response) {
        super.renderHead(component, response);

        Map<String, CharSequence> map = new HashMap<String, CharSequence>(2);
        map.put("selector", jQuerySelector);
        map.put("callbackUrl", getCallbackUrl());
        PackageTextTemplate packageTextTemplate = new PackageTextTemplate(getClass(), "autocomplete.js", "text/javascript");
        String resource = packageTextTemplate.asString(map);
        String uniqueName = Long.toString(Calendar.getInstance().getTimeInMillis());
        response.renderJavaScript(resource, uniqueName);
    }

    @Override
    public void onRequest() {
        Logger logger = LoggerFactory.getLogger(this.getClass());
        logger.info("ajax request received");

        RequestCycle requestCycle = RequestCycle.get();
        Request request = requestCycle.getRequest();
        IRequestParameters irp = request.getRequestParameters();
        StringValue term = irp.getParameterValue("term");
        List<?> matches = getMatches(term.toString());
        String json = convertListToJson(matches);
        requestCycle.scheduleRequestHandlerAfterCurrent(new TextRequestHandler("application/json", "UTF-8", json));
    }

    public abstract List<?> getMatches(String term);
    
    /*
     * Convert List to json object.
     * 
     * Dependency on google-gson library which is 
     * available at http://code.google.com/p/google-gson/
     * and which must be on your classpath when using this
     * library.
     */
    private String convertListToJson(List<?> matches) {
        Gson gson = new Gson();
        String json = gson.toJson(matches);
        return json;
    }

}


All that remains for completing our component's implementation is to implement JQueryAutocompleteTextField and this actually is the easiest part to do. Here's the complete code to JQueryAutocompleteTextField:

package com.wicket.jquery.integration.autocomplete;

import java.util.List;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.IModel;


/**
 *
 * @author jeffrey
 */
public abstract class JQueryAutoCompleteTextField<T extends Object> extends TextField<T> {
    
    private final String jQuerySelector;

    public JQueryAutoCompleteTextField(String id, IModel<T> model, Class<T> type, String jQuerySelector) {
        super(id, model, type);
        this.jQuerySelector = jQuerySelector;
        common();
    }

    public JQueryAutoCompleteTextField(String id, IModel<T> model, String jQuerySelector) {
        super(id, model);
        this.jQuerySelector = jQuerySelector;
        common();
    }

    public JQueryAutoCompleteTextField(String id, Class<T> type, String jQuerySelector) {
        super(id, type);
        this.jQuerySelector = jQuerySelector;
        common();
    }

    public JQueryAutoCompleteTextField(String id, String jQuerySelector) {
        super(id);
        this.jQuerySelector = jQuerySelector;
        common();
    }

    private void common(){
        add(new AbstractJQueryAutocompleAjaxBehavior(jQuerySelector) {

            @Override
            public List<?> getMatches(String term) {
                return JQueryAutoCompleteTextField.this.getMatches(term);
            }
        });
    }
    
    public abstract List<?> getMatches(String term);
}


In the code above we provide numerous constructors allowing the user versatility in how they construct the component. Additionally, each constructor calls the method common which adds an instance of AbstractJQueryAutocompleAjaxBehavior to it. Because in AbstractJQueryAutocompleAjaxBehavior we declared getMatches as abstract we are here forced to provide for its actual implementation. All our implementation does is call JQueryAutocompleteTextField's getMatches method which is also declared as abstract. By defining this abstract method in JQueryAutocompleteTextField our users will have to provide their own implementation which will depend upon their individual use-cases and fulfills our requirement that this component provide a generic implementation allowing it be used however the user's use-case might dictate.

That wraps up our implementation of JQueryAutocompleteTextField but a few things remain to be done. First we need to build the jar file so that we can use JQueryAutocompleteTextField in our Wicket applications and secondly we need to test it. We will cover both beginning with building the jar file.

Building The Jar File

To build the components jar file right click the project node and select Clean And Build. Netbeans will compile the project and package the component in its own jar file.

Notice how none of the libraries we are using to build the component are in the jar file - this is because when we created the project we instructed Netbeans not to include them. Users of the component will now be able to use what ever versions of these dependencies they see fit to use.

Now all that remains is for us to test our component to make sure that it actually works so lets do that now by creating a small Wicket test application using Netbeans. Make sure you have already installed the Wicket Plugin.
  
Testing Our Implementation
  1. From Netbeans main menu select File | New Project | Java Web | Web Application which will open the New Project wizard.
  2. In the wizard enter any name you like for the test project. I named mine WicketAndJQueryAjax and make sure that the Set As Main Project option is selected. Click Next. 
  3. Select either GlassFish Server or Apache Tomcat for the server option and click Next.
  4. From the list of available Frameworks select Wicket and then click Finish.
Netbeans will generate a complete Wicket project including the Wicket jars that the Wicket Plugin contributes. Because our component is dependent upon Wicket v1.5 we will have to replace the ones provided by the Wicket Plugin with the 1.5 versions. So remove all the contributed Wicket jars and replace them with those from the 1.5 distribution. Also, add the google-gson jar file to the project as well. 

We also need to include our components jar also:
  1. Right click on the test project node and select Properties.
  2. From the Categories pane select Libraries and click the Add Project button. 
  3. In the Add Project window select our components project, WicketJQueryIntegration and click the Add Project Jar Files button.
We now want to instruct Netbeans to build our components project when we build our test project:
  1. Right click on the test project node and select Properties and select Libraries from the Categories pane in the Project Properties window.
  2. Select the option Build Required Projects and click the OK button.
Now, whenever we build out test project, Netbeans will check to see if our components project needs to be rebuilt and will do so first before building our test project.

We won't be using Wicket's markup inheritence in our project since it is quite simple so delete the following files from the com.myapp.wicket package:
  • BasePage.java
  • BasePage.html
  • FooterPanel.java
  • FooterPanel.html
  • HeaderPanel.java
  • HeaderPanel.html 
Our test project's structure should now look like this:































Our test project will mimic what my previous article did which was to implement an Autocomplete component that allowed the user to select from a list of states that match their input. 

Open the HomePage.html file in the editor by double clicking on it. When you do, both it and the HomePage.java file will open. This behavior, one of many, is contributed by the Wicket Plugin.

With the HomePage.html file now opened in the editor, replace all of its content with the following:

<!DOCTYPE html> 
<html xmlns:wicket="http://wicket.apache.org"> 
    <head> 
        <meta charset="UTF-8"> 
        <title>Wicket Example</title> 
        <link type="text/css" href="css/start/jquery-ui-1.8.16.custom.css" rel="Stylesheet" />    
        <script type="text/javascript" src="js/jquery.js"></script>
        <script type="text/javascript" src="js/jquery-ui-1.8.16.custom.min.js"></script>
    </head> 
<body>
    <h1>Marrying Wicket And jQuery UI Auto Complete Ajax</h1>
    <h2>jQuery UI Auto Complete State Lookup</h2>
    <form class="jqueryid_form2" wicket:id="form1">
        US State Lookup: <input class="jqueryid_state" type="text" wicket:id="state"/><br/>
    </form>
</body> 
</html>


Notice that in the above there is no reference to a jQuery UI Autocomplete component, just the normal markup one would expect in any Wicket application. Also notice, there is no jQuery ready handler either. The real magic takes place when the component is rendered by Wicket.

Now replace all of the contents of HomePage.java with the following:

/*
 * HomePage.java
 *
 * Created on December 3, 2011, 10:21 AM
 */
package com.myapp.wicket;

import com.wicket.jquery.integration.autocomplete.JQueryAutoCompleteTextField;
import java.util.ArrayList;
import java.util.List;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.PropertyModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HomePage extends WebPage {

    private final Form<HomePage> form1;
    private final TextField<String> stateTextField;
    private String state = "";

    /*
     * A State class jsonified into an array and returned to the client
     */
    static class State {

        State() {
        }

        State(String name) {
            this.name = name;
        }
        String name;
    }

    private static class StatesDb {

        private static final String[] states = new String[]{
            "Alabama",
            "Alaska",
            "Arizona",
            "Arkansas",
            "California",
            "Colorado",
            "Connecticut",
            "Delaware",
            "Florida",
            "Georgia",
            "Hawaii",
            "Idaho",
            "Illinois",
            "Indiana",
            "Iowa",
            "Kansas",
            "Kentucky",
            "Louisiana",
            "Maine",
            "Maryland",
            "Massachusetts",
            "Michigan",
            "Minnesota",
            "Mississippi",
            "Missouri",
            "Montana",
            "Nebraska",
            "Nevada",
            "New Hampshire",
            "New Jersey",
            "New Mexico",
            "New York",
            "North Carolina",
            "North Dakota",
            "Ohio",
            "Oklahoma",
            "Oregon",
            "Pennsylvania",
            "Rhode Island",
            "South Carolina",
            "South Dakota",
            "Tennessee",
            "Texas",
            "Utah",
            "Vermont",
            "Virginia",
            "Washington",
            "West Virginia",
            "Wisconsin",
            "Wyoming"
        };

        static List<State> getStatesLike(String target) {

            List<State> matches = new ArrayList<State>();
            for (String s : states) {
                if (s.toLowerCase().startsWith(target.toLowerCase())) {
                    State state = new State(s);
                    matches.add(state);
                }
            }
            return matches;
        }
        
    }

    public HomePage() {    /*
         * A private static class for states which supports
         * querying for states that are like target and 
         * returning those in a list.
         */

        add(form1 = new Form<HomePage>("form1") {

            @Override
            protected void onSubmit() {
                super.onSubmit();
                Logger logger = LoggerFactory.getLogger(this.getClass());
                logger.info("The user selected: " + state);
            }
        });

        /*
         * A TextField with JQueryAutocompleteBehavior
         */
        form1.add(stateTextField = new JQueryAutoCompleteTextField<String>("state", 
                new PropertyModel<String>(this, "state"), "input.jqueryid_state") {

            @Override
            public List<?> getMatches(String term) {
                List<State> statesLike = StatesDb.getStatesLike(term.toString());
                return statesLike;
            }
        });

    }
}


Notice in the above that we add a JQueryAutoCompleteTextField to the form and that we also provide our own implementation for its getMatches method allowing us to tailor the component to our specific use case which is to find a list of states that match the value of term.

Run the project and it should render the following in the browser:












Now start slowly typing New York into the text box and as you do will be presented with a list of choice matching what characters you have entered:
















Nice, hey? But wait, there's more. Select one of the suggestions from the list and it will propagate the text box. Once propagated, hit Enter to submit the form and now look at the server's log file and you will see log messages that your selection was submitted with the form.

Magicians are never supposed to reveal their tricks to the public but browser pages have no such ethics so now let us peek at the markup that was rendered to the client and relate that back to our component:
































I have highlighted the points of interest in red that relate back to our component. As you can see, the jQuery ready handler itself was contributed and our component tailored it to use the selector we provided it. In addition, it also used the callback url. The success function receives the json object we responded with in our component's onRequest method which had called our getMatches method that we implemented in HomePage.java which returned a List of State objects.

Summary

Wicket v1.5 provides awesome flexibility by allowing easy integration with other component libraries. . The same techniques I used here can be applied in many other cases to create other types of components. The only limits are your imagination so imagine! My imagination tells me that there are many other jQuery UI components just waiting for a similar approach. Hmmm...

I hope you have enjoyed following along with me developing an awesome Wicket/jQuery Ui Autocomplete component. Feel free to leave your comments and please remember to come back soon as I am always cooking something new up to share with you.

Saturday, December 17, 2011

Marrying Wicket And jQuery UI Autocomplete Ajax

* One in a series of articles on Wicket Interfaces & Methods To Master *



Note: the code demonstrated in this article uses the query (v1.6.2) and jquery.ui (v1.8.16) Javascript libraries for client-side scripting and the Google gson library for servers-side JSON support.

Here we pick up from my previous article, Marrying Wicket And jQuery Ajax, but today I will demonstrate how to marry Wicket and jQuery UI, specifically the jQuery UI autocomplete component.

Auto completion allows the user to quickly lookup and select values with minimum key strokes, a fact that has made it a very popular user interface design element. And while it is certainly possible to code the javascript necessary to support auto completion by hand, the jQuery UI library provides a very nice implementation and as a bonus you also get all the graphical sugar that the UI provides.

When I began trying to implement this I tried Googling to find out how others have approached this and as a result I learned that no one seemed to have posted a pure Wicket solution but rather relied upon wiQuery's implementation. As I prefer to not use wiQuery and to roll my own reusable "pure" Wicket based solutions I came up with the solution that you will find here in this article which only uses Wicket 1.5 and the jQuery UI library. So lets roll up our sleeves and get on with it...

Here's the Java code:

/*
 * HomePage.java
 *
 * Created on December 3, 2011, 10:21 AM
 */
package com.myapp.wicket;

import com.google.gson.Gson;
import java.lang.String;
import java.util.ArrayList;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.request.IRequestParameters;
import org.apache.wicket.request.Request;
import org.apache.wicket.request.cycle.RequestCycle;
import org.apache.wicket.request.handler.TextRequestHandler;
import org.apache.wicket.util.string.StringValue;

public class HomePage extends WebPage {

    private final Form<HomePage> form1;
    private final AbstractAjaxBehavior aab1;
    private final TextField<String> state;

    static class State {

        State() {}

        State(String name) {
            this.name = name;
        }
        
        String name;
    }

    public HomePage() {

        add(form1 = new Form<HomePage>("form1"));

        form1.add(state = new TextField<String>("state"));

        /*
         * Ajax Behavior provides an event
         * listener as well as the request
         * handler.
         */

        add(aab1 = new AbstractAjaxBehavior() {

            @Override
            public void renderHead(Component component, IHeaderResponse response) {
                super.renderHead(component, response);
                response.renderJavaScript("var callbackUrl = '" + aab1.getCallbackUrl() + "';", "callbackurl");
            }

            // handle the ajax request
            @Override
            public void onRequest() {
                System.out.println("ajax request received");

                RequestCycle requestCycle = RequestCycle.get();
                Request request = requestCycle.getRequest();
                IRequestParameters irp = request.getRequestParameters();
                StringValue state = irp.getParameterValue("term");
                List<State> statesLike = MockDb.getStatesLike(state.toString());
                String json = convertListToJson(statesLike);
                requestCycle.scheduleRequestHandlerAfterCurrent(new TextRequestHandler("application/json", "UTF-8", json));
            }
        });

    }

    /*
     * Convert List to json object
     */
    private String convertListToJson(List<?> matches) {
        Gson gson = new Gson();
        String json = gson.toJson(matches);
        return json;
    }

    /*
     * A Mock Database
     */
    static class MockDb {

        private static final String[] states = new String[]{
            "Alabama",
            "Alaska",
            "Arizona",
            "Arkansas",
            "California",
            "Colorado",
            "Connecticut",
            "Delaware",
            "Florida",
            "Georgia",
            "Hawaii",
            "Idaho",
            "Illinois",
            "Indiana",
            "Iowa",
            "Kansas",
            "Kentucky",
            "Louisiana",
            "Maine",
            "Maryland",
            "Massachusetts",
            "Michigan",
            "Minnesota",
            "Mississippi",
            "Missouri",
            "Montana",
            "Nebraska",
            "Nevada",
            "New Hampshire",
            "New Jersey",
            "New Mexico",
            "New York",
            "North Carolina",
            "North Dakota",
            "Ohio",
            "Oklahoma",
            "Oregon",
            "Pennsylvania",
            "Rhode Island",
            "South Carolina",
            "South Dakota",
            "Tennessee",
            "Texas",
            "Utah",
            "Vermont",
            "Virginia",
            "Washington",
            "West Virginia",
            "Wisconsin",
            "Wyoming"
        };

        static List<State> getStatesLike(String target) {

            List<State> matches = new ArrayList<State>();
            for (String s : states) {
                if (s.toLowerCase().startsWith(target.toLowerCase())) {
                    State state = new State(s);
                    matches.add(state);
                }
            }
            return matches;
        }
    };
}


In the code above we create an AbstractAjaxBehavior and add it to the page to provide a request handler for the ajax call. Our AbstractAjaxBehavior class overrides two methods:

  1. renderHead, in which we grab the behavior's call back url and contribute it via Javascript to the page where it will be used as the url to call by the jQuery UI autocomplete method.
  2. onRequest, in which we process the ajax request and in which we use the request parameter whose name is 'term' to look up all the states that begin with its value and convert the names of those states to an array of json objects in the form of [{name : "statename"}...]. Finally, we schedule a TextRequestHandler passing that array as a parameter which will be sent back to the client as the result of the ajax call. Note that our response content type is "application/json", "UTF-8". 

And that's really all it takes for Wicket v1.5 to support ajax request that must return json. Now, lets take a look at the markup including the Javascript needed to support our integration with jQuery UI and Wicket:

<!DOCTYPE html> 
<html xmlns:wicket="http://wicket.apache.org"> 
    <head> 
        <meta charset="UTF-8"> 
        <title>Wicket Example</title> 
        <link type="text/css" href="css/start/jquery-ui-1.8.16.custom.css" rel="Stylesheet" />    
        <script type="text/javascript" src="js/jquery.js"></script>
        <script type="text/javascript" src="js/jquery-ui-1.8.16.custom.min.js"></script>
        <wicket:head>
        </wicket:head>    
        <script type="text/javascript" >
        $(document).ready(function(){
            $('input.jqueryid_state').autocomplete({source: function(req, add){
                //pass request to server  
                $.ajax({
                    url: callbackUrl,
                    type: 'GET',
                    cache: false,
                    data: req,
                    dataType: 'json',
                    success: function(json){
                        var suggestions = [];  

                        //process response  
                        $.each(json, function(i, val){  
                            suggestions.push(val.name);  
                        });
                        
                        // call autocomplet callback method with results
                        add(suggestions);
                    },
                    error: function(XMLHttpRequest, textStatus, errorThrown){
                        //alert('error - ' + textStatus);
                        console.log('error', textStatus, errorThrown);
                    }
                });            
            }});
        });
        </script>
    </head> 
<body>
    <h1>Marrying Wicket And jQuery Ajax</h1>
    <h2>jQuery UI Auto Complete State Lookup</h2>
    <form class="jqueryid_form2" wicket:id="form1">
        US State Lookup: <input class="jqueryid_state" type="text" wicket:id="state"/><br/>
                    <div id="statelist"/>
    </form>
</body> 
</html>


In the above Javascript code we create a jQuery ready handler which sets up jQuery UI autocomplete. Here we use a json object that contains the property named source and which provides a callback function that autocomplete will call to retrieve the results matching the user's input. In this callback we use jQuery's ajax method to make an ajax call back to the Wicket event listener whose url is stored in the global variable callbackUrl which we obtained from the AbstractAjaxBehavior we created in our Java code.

Finally, the result from the ajax call, which is an array of json objects whose val properties are the names of the states are passed back to autocomplete by calling the add callback method. jQuery Ui autocomplete uses these to present a list of options to the user as can be seen from the following screen shot:

That's pretty impressive I think, especially considering the minimal amount of code we had to write, both on the client and the server. Being able to use this technique along with using Wicket's default Ajax implementation is empowering, allowing us to use the right technologies that best suits the use case.

I hope you enjoyed following along with me and please remember to come back soon because I always have something interesting to write about Wicket.

Monday, September 5, 2011

How To Validate And Block Ajax Callbacks

* One in a series of articles on Wicket Interfaces & Methods To Master *

Wicket allows you to easily add Ajax support to Wicket components by adding some concrete subclass of the AbstractAjaxBehavior class to them which ties a Javascript DOM event on the client to an event listener in an AjaxEventBehavior or some subclass of.
For instance, suppose you want to add Ajax support to a Wicket component backing an input text element that supports the DOM onkeyup event. Doing so is easily accomplished using the following markup and Java code fragments:

Markup
  1:     <body> 
  2:         <h1>Default Wicket Ajax</h1>
  3:         <form wicket:id="defaultajaximplmentationform">
  4:             Enter Something <input type="text" wicket:id="enterSomething"/>
  5:         </form>
  6:         <div>You entered: <span class="message" wicket:id="message"/></div>
  7:     </body> 
  8: 
Java
  1: public class HomePage extends WebPage {
  2: 
  3:     private Form<HomePage> form;
  4:     private TextField<String> textField;
  5:     private Label message;
  6:     private String enterSomething = "";
  7:     
  8:     public HomePage() {
  9:         form = new Form<HomePage>("defaultajaximplmentationform");
 10:         add(form);
 11:         textField = new TextField<String>("enterSomething", new PropertyModel<String>(this, "enterSomething")); 
 12:         textField.add(new AjaxFormSubmitBehavior("onkeyup") {
 13: 
 14:             @Override
 15:             protected void onSubmit(AjaxRequestTarget target) {
 16:                 // do something meaningful here like updating the database
 17:                 target.addComponent(message);
 18:             }
 19: 
 20:             @Override
 21:             protected void onError(AjaxRequestTarget target) {
 22:                 throw new UnsupportedOperationException("Not supported yet.");
 23:             }
 24:         });
 25:         form.add(textField);
 26:         message = new Label("message", new PropertyModel<String>(this, "enterSomething"));
 27:         message.setOutputMarkupId(true);
 28:         add(message);
 29:     }
 30: 
 31: }
 32: 
Looking at the Java code above we can see that I added an Ajax callback for the Javascript onkeyup event to the textfield component by adding an AjaxFormSubmittingBehavior to it. When rendered the AjaxFormSubmittingBehavior contributes Javascript code to the input element's onkeyup event that submits the form that the input element is a child of. The Javascript that submits the form calls into Wicket's Ajax Javascript library whenever the user presses and releases a key when the input element has the input focus.Here is what the rendered markup looks like:
  1: 
  2: <!DOCTYPE html> 
  3: <html xmlns:wicket="http://wicket.apache.org"> 
  4:     <head> 
  5:         <meta charset="UTF-8"> 
  6:         <title>Wicket Example</title> 
  7:         <style type="text/css"> 
  8:             span.message {
  9:                 color: #0000FF;
 10:             }
 11:         </style> 
 12:     <script type="text/javascript" src="resources/org.apache.wicket.markup.html.WicketEventReference/wicket-event.js"></script>

 13: <script type="text/javascript" src="resources/org.apache.wicket.ajax.WicketAjaxReference/wicket-ajax.js"></script>

 14: <script type="text/javascript" src="resources/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/wicket-ajax-debug.js"></script>

 15: <script type="text/javascript" id="wicket-ajax-debug-enable"><!--/*--><![CDATA[/*><!--*/
 16: wicketAjaxDebugEnable=true;
 17: /*-->]]>*/</script> 
 18: 

 19: </head> 
 20:     <body> 
 21:         <h1>Default Wicket Ajax</h1> 
 22:         <form wicket:id="defaultajaximplmentationform" id="defaultajaximplmentationform4" method="post" action="?wicket:interface=:1:defaultajaximplmentationform::IFormSubmitListener::"><div style="display:none"><input type="hidden" name="defaultajaximplmentationform4_hf_0" id="defaultajaximplmentationform4_hf_0" /></div> 
 23:             Enter Something <input type="text" wicket:id="enterSomething" value="" name="enterSomething" id="enterSomething5" onkeyup="var wcall=wicketSubmitFormById('defaultajaximplmentationform4', '?wicket:interface=:1:defaultajaximplmentationform:enterSomething::IActivePageBehaviorListener:0:&amp;wicket:ignoreIfNotActive=true', null,function() { }.bind(this),function() { }.bind(this), function() {return Wicket.$$(this)&amp;&amp;Wicket.$$('defaultajaximplmentationform4')}.bind(this));;"/> 
 24:         </form> 
 25:         <div>You entered: <span class="message" wicket:id="message" id="message6"></span></div> 
 26:     </body> 
 27: </html> 

Line 23 in the rendered markup above shows that the AjaxFormSubmittingBehavior added the onkeyup event to the input element. The Javascript code it added to the event is the following:

var wcall=wicketSubmitFormById('defaultajaximplmentationform7', '?wicket:interface=:2:defaultajaximplmentationform:enterSomething::IActivePageBehaviorListener:0:&amp;wicket:ignoreIfNotActive=true', null,function() { }.bind(this),function() { }.bind(this), function() {return Wicket.$$(this)&amp;&amp;Wicket.$$('defaultajaximplmentationform7')}.bind(this));;

The Javascript added by AjaxFormSubmittingBehavior calls wicketSubmitFormById which is a method that resides in the wicket-event.js, a Javascript file that was also contributed by AjaxFormSubmittingBehavior to the page.

All of Wicket's numerous Ajax components and behaviors work similarly which is fine if you don't need to do anything on the client after the DOM event and before the Ajax call back to the server. But suppose you want to perform validation before the Ajax call back to the server and possibly block the call back to the server if validation fails, how can you do this?

Well, the solution is actually quite easy but poorly documented. Even the holly grail of Wicket books, Wicket In Action, doesn't cover this because it was written before the solution presented here in this article was provided in the Wicket library so many readers of the book are left scratching their heads in confusion.

Prepending Your Own Javascript To Wicket's Generated Javascript

The solution requires that you override the getAjaxCallDecorator method defined in AbstractDefaultAjaxBehavior in your own behaviors to return an implementation of IAjaxCallDecorator that prepends the Javascript that Wicket generates with your own Javascript which can do anything that your use case might require such as validation and preventing the Ajax call to the server should the validation fail.

First, lets take a look at IAjaxCallDecorator:

  1: public interface IAjaxCallDecorator extends IClusterable
  2: {
  3:   /**
  4:    * Name of javascript variable that will be true if ajax call was made, false otherwise. This
  5:    * variable is available in the after script only.
  6:    */
  7:   public static final String WICKET_CALL_RESULT_VAR = "wcall";
  8: 
  9:   /**
 10:    * Decorates the script that performs the ajax call
 11:    * 
 12:    * @param script
 13:    * @return decorated script
 14:    */
 15:   CharSequence decorateScript(CharSequence script);
 16: 
 17:   /**
 18:    * Decorates the onSuccess handler script
 19:    * 
 20:    * @param script
 21:    * @return decorated onSuccess handler script
 22:    */
 23:   CharSequence decorateOnSuccessScript(CharSequence script);
 24: 
 25:   /**
 26:    * Decorates the onFailure handler script
 27:    * 
 28:    * @param script
 29:    * @return decorated onFailure handler script
 30:    */
 31:   CharSequence decorateOnFailureScript(CharSequence script);
 32: 
 33: }
 34: 

This interface declares 3 methods that must be implemented, all taking a CharSequence script parameter and returning a CharSequence. The CharSequence script parameter passed to these methods is the Javascript that Wicket generated to call it's Ajax Javascript library and that it assigns as the DOM event handler on the client.

Wicket provides a convenience class, AjaxCallDecorator, which is an adapter class which provides default implementations for these 3 methods.

  1: public abstract class AjaxCallDecorator implements IAjaxCallDecorator
  2: {
  3: 
  4:   /**
  5:    * 
  6:    */
  7:   private static final long serialVersionUID = 1L;
  8: 
  9:   /**
 10:    * @see org.apache.wicket.ajax.IAjaxCallDecorator#decorateScript(CharSequence)
 11:    */
 12:   public CharSequence decorateScript(CharSequence script)
 13:   {
 14:     return script;
 15:   }
 16: 
 17:   /**
 18:    * @see org.apache.wicket.ajax.IAjaxCallDecorator#decorateOnSuccessScript(CharSequence)
 19:    */
 20:   public CharSequence decorateOnSuccessScript(CharSequence script)
 21:   {
 22:     return script;
 23:   }
 24: 
 25:   /**
 26:    * @see org.apache.wicket.ajax.IAjaxCallDecorator#decorateOnFailureScript(CharSequence)
 27:    */
 28:   public CharSequence decorateOnFailureScript(CharSequence script)
 29:   {
 30:     return script;
 31:   }
 32: 
 33: 
 34: }
 35: 

To add Javascript that will call our validation routine and prevent the Ajax call should validation fail is just a matter of implementing the AjaxCallDecorator's decorateScript method and prepending script with our own Javascript which I will discuss next but first lets define a use case and build the implementation around that.

Our use case is the following:

Provide a form with an input text field in which the user can enter some text. The validation rules specify that the text the user enters should be at least 3 characters or they shouldn't be allowed to submit the form (via Ajax).

Now here's the implementation:

Markup

The markup we provide is very straight forward. It contains a form with a wicket id of form that has 1 input text element which we give a wicket id of enterSomething. We also provide a button the user can click to submit the form via Ajax which we give a wicket id of submitbutton. When the form is submitted we will echo what the user enters in a label which we have assigned the wicket id of message.

  1: <!DOCTYPE html> 
  2: <html xmlns:wicket="http://wicket.apache.org"> 
  3:     <head> 
  4:         <meta charset="UTF-8"> 
  5:         <title>Wicket Example</title> 
  6:         <script type="text/javascript" src="javascript/jquery.js"></script>
  7:         <style type="text/css">
  8:             span.message {
  9:                 color: #0000FF;
 10:             }
 11:         </style>
 12:     </head> 
 13:     <body> 
 14:         <h1>Wicket Ajax With Client-Side Validation Using Script Prepending</h1>
 15:         <form wicket:id="form">
 16:             Enter at least 3 characters to call the AJAX callback: <input type="text" wicket:id="enterSomething"/>
 17:         </form>
 18:         <button wicket:id="submitbutton">Submit</button>
 19:         <div>You entered: <span class="message" wicket:id="message"/></div>
 20:     </body> 
 21: </html>
 22: 
Java

On the server side we create the Wicket components corresponding to the markup elements discussed above. The key point here is that for the button I am using Wicket's AjaxSubmitLink component whose implementation adds an AjaxFormSubmitBehavior which will contribute the Javascript code for the click event on the button to submit the form back to the server using Ajax. If you spy the source code for AjaxSubmitLink you'll see that it exposes the AjaxFormSubmitBehavior's getAjaxCallDecorator method which we can override to return our own implementation of IAjaxCallDecorator:
  1: public class HomePage extends WebPage {
  2: 
  3:     private Form<HomePage> form;
  4:     private TextField<String> textField;
  5:     private Label messageLabel;
  6:     private String message = "";
  7:     private String enterSomething = "";
  8:     
  9:     public HomePage() {
 10:         form = new Form<HomePage>("defaultajaximplmentationform");
 11:         add(form);
 12:         textField = new TextField<String>("enterSomething", new PropertyModel<String>(this, "enterSomething")); 
 13:         textField.setOutputMarkupId(true);
 14:         textField.add(new PreventFormSubmitOnEnterBehavior());
 15:         form.add(textField);
 16:         add(new AjaxSubmitLink("submitbutton", form) {
 17: 
 18:             @Override
 19:             public void renderHead(HtmlHeaderContainer container) {
 20:                 super.renderHead(container);
 21:                 String javascript = "validate = function(){ var inputElement = $('#" + textField.getMarkupId() + "'); if($(inputElement).val().length < 3){ $(inputElement).css('background-color', '#ff0000'); return false; }else{ $(inputElement).css('background-color', '#ffffff'); return true; } }";
 22:                 container.getHeaderResponse().renderJavascript(javascript, "entersomethingvalidation");
 23:             }
 24: 
 25:             @Override
 26:             protected IAjaxCallDecorator getAjaxCallDecorator() {
 27:                 return new AjaxCallDecorator() {
 28: 
 29:                     @Override
 30:                     public CharSequence decorateScript(CharSequence script) {
 31:                         PrependingStringBuffer psb = new PrependingStringBuffer(script.toString());
 32:                         psb.prepend("if(validate() == false) return false;");
 33:                         return psb.toString();
 34:                     }
 35:                     
 36:                 };
 37: 
 38:             }
 39: 
 40:             @Override
 41:             protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
 42:                 System.out.println("yada yada");
 43:                 // do something meaningful here like updating the database
 44:                 message = enterSomething;
 45:                 enterSomething = "";
 46:                 target.addComponent(textField);
 47:                 target.addComponent(messageLabel);
 48:             }
 49:         });
 50:         messageLabel = new Label("message", new PropertyModel<String>(this, "message"));
 51:         messageLabel.setOutputMarkupId(true);
 52:         add(messageLabel);
 53:     }
 54: 
 55: }
 56: 

Above we create an instance of AjaxCallDecorator and we override its decorateScript method to prepend the script parameter with our own Javascript on line 30. We prepend Javascript on line 32  that calls our own Javascript function validate which we contributed to the page in our overriding of the renderHead method on line 19. To prevent the Ajax call back to the server should our validate function return false the prepended Javascript returns false.

  1: @Override
  2: protected IAjaxCallDecorator getAjaxCallDecorator() {
  3:   return new AjaxCallDecorator() {
  4: 
  5:       @Override
  6:       public CharSequence decorateScript(CharSequence script) {
  7:     PrependingStringBuffer psb = new PrependingStringBuffer(script.toString());
  8:     psb.prepend("if(validate() == false) return false;");
  9:     return psb.toString();
 10:       }
 11: 
 12:   };
 13: 
 14: }

When run the markup for HomePage is rendered as follows:

  1: 
  2: <!DOCTYPE html> 
  3: <html xmlns:wicket="http://wicket.apache.org"> 
  4:     <head> 
  5:         <meta charset="UTF-8"> 
  6:         <title>Wicket Example</title> 
  7:         <script type="text/javascript" src="../javascript/jquery.js"></script> 
  8:         <style type="text/css"> 
  9:             span.message {
 10:                 color: #0000FF;
 11:             }
 12:         </style> 
 13:     <script type="text/javascript" ><!--/*--><![CDATA[/*><!--*/
 14: $(document).ready(function(){$('#enterSomething5').live('keypress', function(e){var c = e.which ? e.which : e.keyCode;if (c == 13) {return false;}});});
 15: /*-->]]>*/</script> 
 16: 

 17: <script type="text/javascript" src="resources/org.apache.wicket.markup.html.WicketEventReference/wicket-event.js"></script>

 18: <script type="text/javascript" src="resources/org.apache.wicket.ajax.WicketAjaxReference/wicket-ajax.js"></script>

 19: <script type="text/javascript" src="resources/org.apache.wicket.ajax.AbstractDefaultAjaxBehavior/wicket-ajax-debug.js"></script>

 20: <script type="text/javascript" id="wicket-ajax-debug-enable"><!--/*--><![CDATA[/*><!--*/
 21: wicketAjaxDebugEnable=true;
 22: /*-->]]>*/</script> 
 23: 

 24: <script type="text/javascript" id="entersomethingvalidation"><!--/*--><![CDATA[/*><!--*/
 25: validate = function(){ var inputElement = $('#enterSomething5'); if($(inputElement).val().length < 3){ $(inputElement).css('background-color', '#ff0000'); return false; }else{ $(inputElement).css('background-color', '#ffffff'); return true; } }
 26: /*-->]]>*/</script> 
 27: 

 28: </head> 
 29:     <body> 
 30:         <h1>Wicket Ajax With Client-Side Validation Using Script Prepending</h1> 
 31:         <form wicket:id="defaultajaximplmentationform" id="defaultajaximplmentationform6" method="post" action="?wicket:interface=:1:defaultajaximplmentationform::IFormSubmitListener::"><div style="display:none"><input type="hidden" name="defaultajaximplmentationform6_hf_0" id="defaultajaximplmentationform6_hf_0" /></div> 
 32:             Enter at least 3 character to call the AJAX callback: <input type="text" wicket:id="enterSomething" value="" name="enterSomething" id="enterSomething5"/> 
 33:         </form> 
 34:         <button wicket:id="submitbutton" id="submitbutton7" onclick="if(validate() == false) return false;var wcall=wicketSubmitFormById('defaultajaximplmentationform6', '?wicket:interface=:1:submitbutton::IActivePageBehaviorListener:0:&amp;wicket:ignoreIfNotActive=true', 'submitbutton' ,function() { }.bind(this),function() { }.bind(this), function() {return Wicket.$$(this)&amp;&amp;Wicket.$$('defaultajaximplmentationform6')}.bind(this));;; return false;">Submit</button> 
 35:         <div>You entered: <span class="message" wicket:id="message" id="message8"></span></div> 
 36:     </body> 
 37: </html> 

Notice that in the above markup on line 34 that our button's onclick event includes our prepended Javascript. Below is the Javascript we contributed by prepending in bold blue highlight:

onclick="if(validate() == false) return false;var wcall=wicketSubmitFormById('form6', '?wicket:interface=:1:submitbutton::IActivePageBehaviorListener:0:&amp;wicket:ignoreIfNotActive=true', 'submitbutton' ,function() { }.bind(this),function() { }.bind(this), function() {return Wicket.$$(this)&amp;&amp;Wicket.$$('form6')}.bind(this));;; return false;"

And here's what HomePage looks like when rendered in the browser:


2011-09-17 12h22_23


If you enter 2 characters or less and then click the submit button you will see the following:


2011-09-17 12h25_31


When we clicked submit the button's onclick event was called where we call validate. In this case, because validation failed false was returned and the Ajax call back to the server was blocked by returning false.

When we enter 3 characters and click submit here's what we get:


2011-09-17 12h26_43


Since we entered 3 characters validation succeeded and returned true so the Ajax call back to the server wasn't blocked.. On the server we assigned the value of input's model to the message's model and then we cleared out the input's model to an empty string. Then we added the input and message components to the AjaxTarget which will cause them to render in the response by replacing their markup in the DOM.

Summary

As this article has shown, Wicket's enables you to to prepend its Ajax calls to the server with your own Javascript giving you great control over your Ajax processing. What might not have been so obvious is that Wicket doesn't just limit you to prepending and validation - you can also contribute Javascript that will be called in the success handler and the failure handler as well but those are subjects for a future article.