Dynamic dropdown (Country/state) with dwr & spring

February 9th, 2009 | Tags: , , ,

In my earlier article I had detailed how to get DWR working with spring. Once you get that done, how exactly do you use it? Even though DWR provides a very powerful debugging page, a real-world example never hurts. :)

I’ll construct a simple page which will present the user with a list of countries (populated via DWR on body load). Once the user selects a country he will either see a text box or another dropdown select list. If we have an entry of all the states present in that country, we show him a select. If we don’t have the list of states for a country we show him a box to enter the name of the state into.

The data which we use for the example is just dummy data and you can download it from here.

First the dao that’ll retrieve all this data to us:

package com.codercorp.dwr;

import java.util.List;

public interface GeneralDao {

	List<Country> getAllCountries();

	List<State> getStatesForCountry(int countryId);
}

It’s implementation :

package com.codercorp.dwr;

...

@Transactional
public class JdbcGeneralDao implements GeneralDao {

	private DataSource	dataSource;

	@Override
	public List<Country> getAllCountries() {
		ParameterizedRowMapper<Country> mapper = new ParameterizedRowMapper<Country>() {

			@Override
			public Country mapRow(ResultSet rs, int arg1) throws SQLException {
				Country country = new Country();
				country.setId(rs.getInt("numcode"));
				country.setName(rs.getString("printable_name"));
				return country;
			}
		};
		String sql = "select * from country";
		SimpleJdbcTemplate sjt = new SimpleJdbcTemplate(getDataSource());
		return sjt.query(sql, mapper, Collections.emptyMap());
	}

	@Override
	public List<State> getStatesForCountry(int countryId) {
		ParameterizedRowMapper<State> mapper = new ParameterizedRowMapper<State>() {

			@Override
			public State mapRow(ResultSet rs, int arg1) throws SQLException {
				State state = new State();
				Country country = new Country();
				country.setId(rs.getInt("ccode"));
				country.setName(rs.getString("printable_name"));
				state.setCountry(country);
				state.setId(rs.getInt("id"));
				state.setName(rs.getString("name"));
				return state;
			}
		};
		SimpleJdbcTemplate sjt = new SimpleJdbcTemplate(getDataSource());
		String sql = "select s.*, c.* from states s, country c where s.ccode = c.numcode and c.numcode = " + countryId;
		return sjt.query(sql, mapper, Collections.emptyMap());
	}
// getters and setters

}

You can write a hibernate implementation of the above DAO if you so wish, our configuration makes sure that you can switch out one for the other at any time.

This bean, generalDao, must now be exposed to external clients through DWR. To make this possible, while defining the generalDao bean in your spring add some extra configuration like this :

<bean id="generalDao" class="com.codercorp.dwr.JdbcGeneralDao">
	<property name="dataSource" ref="dataSource" />
	<dwr:remote javascript="generalDao">
		<dwr:include method="getAllCountries" />
		<dwr:include method="getStatesForCountry" />
		<dwr:convert type="bean" class="com.codercorp.dwr.Country">
			<dwr:include method="id" />
			<dwr:include method="name" />
		</dwr:convert>
		<dwr:convert type="bean" class="com.codercorp.dwr.State">
			<dwr:include method="id" />
			<dwr:include method="name" />
			<dwr:include method="country" />
		</dwr:convert>
	</dwr:remote>
</bean>

That’s it, your bean is now exposed. Start your container and navigate to /YOURAPP/dwr/. You will see generalDao listed there. Click on it to see what methods have been exposed.

Now to use this data thats been exposed by the bean. We must write a jsp:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
<script type='text/javascript'
	src='/dwr-example/dwr/interface/generalDao.js'></script>
<script type='text/javascript' src='/dwr-example/dwr/engine.js'></script>
<script type='text/javascript' src='/dwr-example/dwr/util.js'></script>
<script type="text/javascript">
	var loadstart = function(data) {
		dwr.util.removeAllOptions('countrylist');
		dwr.util.addOptions('countrylist', data, 'id', 'name');
	}
</script>
</head>
<body onload="generalDao.getAllCountries(loadstart);">
Select country : 
<select id="countrylist" name="countrylist" onchange="loadStates();">
</select>
<br /><br /><br />
<div id="s_s" style="display: none;">Select state : <select id="statelist"
	name="statelist">
</select></div>
<div id="s_t" style="display: none;">
Write state name : <input type="text" name="state" id="state" />
</div>
<script type='text/javascript'>
	var callback = function(c) {
		alert(c.length);
	}
	function loadStates() {
		var country = dwr.util.getValue('countrylist');
		generalDao.getStatesForCountry(country, scallback);
	}
	var scallback = function(data) {
		var size = data.length;
		if (size == 0) {
			alert("Nothing found");
			document.getElementById('s_s').style.display = 'none';
			document.getElementById('s_t').style.display = 'block';
		} else {
			alert(size);
			document.getElementById('s_t').style.display = 'none';
			document.getElementById('s_s').style.display = 'block';
			dwr.util.removeAllOptions('statelist');
			dwr.util.addOptions('statelist', data, 'id', 'name');
		}
	}
</script>
</body>
</html>

I hope thats easy to understand. I have created two divs, one for the list of states and other for the manual entry of state name. Depending on the kind of response I recieve from dwr, I hide one and show the other. Check out the loadstartup function between lines 12 and 17. That function is called after the body of the document loads and thats what populates our list of countries.

Once you select a country the loadStates() function fires. This function retrieves the list of states for the selected country from the database. If it doesn’t find any countries it hides the div containing the select box and displays the div containing the text box. If it does find states, it then does the opposite.

If you want to display a loading message, you must call

dwr.util.useLoadingMessage();

once. That’ll tell DWR to show the user a gmail style loading message everytime it’s talking to the server. You can read about it in the dwr docs.

  1. Anonymous
    September 3rd, 2009 at 12:53
    Quote | #1

    Hey Buddies,
    Does anybody know how to integrate spring’s wizard controller with DWR?

    here I’ve seen the ex of populating combo boxes dynamically and i’m implementing the same thing with the help of Jsp > Spring’s Wizard Controller > Service > DAO(Hibernate Queries),i mean i’m populating my combo box values with the help of Controller as here in this eg,only DAO,DWR and Jsp are there in picture.i wanna include my wizard controller(which is interacting with jsp and fetches the data from DAO through hibernate query via Service)in this picture.so can anybody suggest me how to do it?

    Thanks in advance :)

    With Regards,
    Barkha Jasani

  2. zdfasdf
    July 29th, 2010 at 00:07
    Quote | #2

    Way to post your code using 10% of the available screen width at best.

  3. abhijit bora
    August 2nd, 2010 at 16:42
    Quote | #3

    Article is very helpful in understanding the DWR works…..
    Here i am just confused about the script

    dwr-example/dwr/interface/generalDao.js
    dwr-example/dwr/engine.js
    dwr-example/dwr/util.js

    Sir May have these javascript in my mail to get vivid knowledge about this code..
    Thanx in advance

  4. Yogesh Chawla
    October 1st, 2010 at 21:40
    Quote | #4

    Wow, this page coupled with this example:

    https://localhost:8443/TrafficStopData/dwr/test/generalDao

    are just fantastic. It would be great if you could get in touch with the Spring folks and get this included in some of the more widely distributed Spring documentation.

    Dude, you rock!

  5. Yogesh Chawla
    October 1st, 2010 at 21:41
    Quote | #5
  6. Rajesh Kumar
    February 22nd, 2013 at 03:58
    Quote | #6

    Hey Dude,

    Thank you very much for the terrific article! I improvised a bit with the suggestions you made in this article. It was very helpful for my project.

Comments are closed.