Loading...

Friday, June 29, 2007

AJAX though DWR: Populate Select Lists Dynamically

Intro
In my first article about Direct Web Remoting (DWR), I mentioned a simple example of what DWR has to offer.

A quick example is a "City" drop down list that depends on a "State" drop down list. In most websites, a user chooses the "State" and then watches the page refresh as it goes to the server to build the "City" drop down list.With AJAX, you can populate the "City" drop down list without ever having to refresh the page.


In this article I will provide an explanation on how this can be done.

Disclaimer *
It should be noted that this article is for learning purposes only, the source code should not be used as in production. You will need to modify what I have provided to fit your project's design. This article is simply to show you how to populate a drop down list based on another drop down list's chosen value though DWR. Also, select list and drop down list are used interchangeably. Lastly, for this example, I am going to use Struts as my web application framework.

Setup
First, you will need to setup DWR in your project. This article will show you how to set up DWR, please follow these steps before moving on if you have not setup DWR in your project. If you would like to follow along, the source code to this example can be found here.

The Players

DTOs
For this example, we are going to have two data transfer objects (DTOs) that will move our drop down list data from the data access object (DAO) to the front-end. They will be called City & State .

(DTOs)


If Unified Modelling Language (UML) is not in your skill set, please take a look at this article here. Basically, this UML diagram says that City is linked to State and that the State object can have many Cities i.e. Array of type City[].

DAO
We are going to to use a DAO called CityStateDAO, which will populate the City & State objects

(DAO)


getStates(): Method which returns all states.
getCitiesByStates(id) : Method which returns Cities based on their State.

*When you eventually look at the source, you will notice the code is not connecting to any type of database. In the real world, your DAO would be connecting to a database and gathering data instead of building and filling arrays manually.

Struts Action Class - CityStateAction
In our Struts Action Execute() method, which executes before the page loads; we are going to gather the data needed to fill our State drop down list and put it in the request so it is ready to go upon the page loading.


Line 1: Creates an Instance of CityStateDAO.
Line 2. Calls the getStates() method inside of CityStateDAO to build the State[] Array.
Line 3. Places the State[] Array in the request for use by the CityState.jsp upon loading.

Struts Form Class - CityStateForm
The Struts Form Class will simply have a city and state that would capture the city and state values upon submitting. *Note: We will not be submitting in this example.


Struts Config File - struts-config.xml
And of course the Struts Action and Form classes would be declared in the struts config-file.


DWR Config File - dwr.xml
Now it's time for the good stuff, in order to use the State and City DTOs, we need to expose them to DWR and give it permission to see them. The same goes for the CityStateDAO; DWR needs to know where it exist and whether it has permission to use that class.


* I highly recommend against allowing DWR direct access to your DAOs. There is usually some type of buffer in between the front-end (DWR) and backend components (DAOs) such as a Facade. Where to call the DAOs depends on your framework and design.

JavaServer Pages (JSP) - CityState.jsp
All the xml files and java classes we have went over so far exist in order to support the CityState.jsp. There's only about 20 lines of code that make the magic happen. The magic being that the City drop down list will update when the State value is changed without the entire page refreshing. Thereby, giving the user a smooth interface experience.


The above is the first half of the JSP. At the top, we setup our tag libraries we are going to use in our JSP. In this example, we are going to use JavaServer Pages Standard Tag Library (JSTL) to build our HTML compoments i.e. Select List.

After the tag library declarations, we call the nessecary DWR javascript libraries that we need to accomplish our task. You will notice there is a call to a script for CityStateDAO.js, we set this up in the DWR.xml file when we exposed it. The beauty of DWR is that it does all the AJAX work in the background for you. Now we are free to call CityStateDAO methods and use the data they return in our drop down lists.

Next, you will also notice two javascript functions:

The first is the onStateChange() function. This function is called when the State value is changed in the State drop down list.

This function, in turn, calls our exposed CityStateDAO.getCitiesByState(state) java method to return a list of Cities objects based on the State that was choosen. DWR does all the conversions of Java objects to Javascript objects for you. After the data is returned, we simply treat it like any other javascript array.

$("stateList").value

  • Is the same as using getElementById("stateList").value

CityStateDAO.getCitiesByState($("stateList").value, populateCities);

  • Calls the getCitiesByState java method and passes in the choosen state.

The first function then passes the results to the second function populateCities(data) whoose job is to re-populate the City drop down list based on the State that was choosen. It uses methods provided by the DWR utility library to accomplish this.

DWR Utilities

Removes all options from a List:
DWRUtil.removeAllOptions("cityList");

  • "cityList" is the id of the html option list we want to remove all options from.


Adds options to a list:
DWRUtil.addOptions("cityList", data, "id", "name" );

  • "data" is the returned array of Cities provided by the getCitiesByState(state) method.
  • "id" is a field within the City object, this will populate the value attribute of an HTML option tag.
  • "name" is a field within the City object, this will populate the text of an HTML option tag.

Now let's take a look at the second half of the JSP which includes the HTML for the drop down lists.


Note: Each HTML element should have it's own ID so DWR can reference it.

When the page initially loads, the State list is populated because we placed a State[] Array in the request and called it "stateList". This was performed by the Struts Action class. However, this is the only time we are going to call the CityStateDAO from the Action class.

From now on, we retrive data using the javascript functions we reviewed earlier. If you look at the State HTML option list, you see it calls the onStateChange() function for it's onChange event. When a user changes the State, the onStateChange() fucntion will fire off the populateCities() function and a new list of Cities will magically appear, without a page refresh; giving the folks at home that rich user experience they so righfully crave.


State is Virgnia


State Changed to Texas


And that my friends, are the baiscs on how to use DWR.

The source to this article can be downloaded here.
The war file for this project can be found here
The previous article on DWR is right here.
More examples on DWR can be found here.

Have any comments? post 'em!

8 comments:

Asif said...

Very helpful example! I used it in my code, and it works great. Believe me, I was just staring at my working JSP page in sheer disbelief when it worked. Thanks so much Pedro.

cnu said...

Great example,helped a lot in building dwr based application.keep up the good work.Thanks a lot pedro.

madh_n said...

This is a very good example.
I'm using it in my module but i've a problem on a particular system on mozilla 2.0.0.18 version this is failing.Even no pop up is coming.
What could be the problem?any answers pls?

The Wolf said...

madh_n I wish I could help you on that but I didn't test the example outside of IE.

Ketan said...

Hi,
Nice sample example.
I got my solution...
thanks.

Anonymous said...

Very Good article.

leejeok said...

fantastic tutorial..
thanks for sharing.

leejeok said...

work fine on mozilla 3.5 too..