Spring JS – Ajax Popup with list refresh

The concept

I have been working with Spring-JS for a while now and have noticed that there doesn’t seem to be too many examples out there. This tutorial should hopefully address one common usage of Spring JS and its Ajax simplifications.

One common use of any Ajax framework is to have a page list a number of items. Then allow the user to add to those items. When adding an item a popup is displayed asking for the item details. Upon saving the item the popup is closed and the list underneath is refreshed. All actions working through Ajax and without changing page.

As a flow this would be:

  • User clicks to list items
  • User clicks to add items
  • Popup displayed asking for new item details
  • User clicks save within popup
  • If new details passes validation
  • List of items refreshed and popup closed

Getting hold of the sample code

I have hosted the completed project on GitHub. So please feel free to clone the repository @ git://github.com/eggsy84/SpringPopupRefreshList.git

Also if anyone has any contributions to add to the project please drop me an email or submit a request via GitHub for write access. The GitHub page is https://github.com/eggsy84/SpringPopupRefreshList. You can also download the project from this site. The rest of the tutorial will continue assuming you have grabbed the source code.

The servlet XML

We firstly need to configure our Spring MVC through the servlet-context.xml file. For Spring-JS and partial rendering to work we define the use of Apache Tiles as our view resolving mechanism. We can do this by simply configuring a few beans:

<beans:bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
	<beans:property name="definitions">
    		<beans:list>
      			<beans:value>/WEB-INF/tile-defs/tile-defs.xml</beans:value>
 		</beans:list>
	</beans:property>
</beans:bean>
 
<beans:bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
	<beans:property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
</beans:bean>

The main item to note here is the location of our tile defintions file. This shall be discussed shortly. The final thing to add to the servlet-xml file is to tell Spring to context scan our project for Spring controllers.

<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
 
<context:component-scan base-package="uk.co.eggsylife.controller" />

We’re informing Spring to scan the ‘uk.co.eggsylife.controller’ package. The complete servlet-context.xml can be seen online.

The configuration XML

For the purpose of this tutorial, the application lists students and allows the user to add students. The ‘students’ bean acts as an in-memory database that is added to at runtime. It is a simple Java ArrayList of Student model objects. Typically you will have your own model objects and different CRUD operations on those objects.

<bean id="students" class="java.util.ArrayList">
	<constructor-arg>
		<list>
			<bean class="uk.co.eggsylife.persistent.Student">
				<property name="studentNumber" value="1" />
				<property name="firstName" value="John" />
				<property name="lastName" value="Smith" />
			</bean>
			<bean class="uk.co.eggsylife.persistent.Student">
				<property name="studentNumber" value="2" />
				<property name="firstName" value="Jane" />
				<property name="lastName" value="Smith" />
			</bean>
		</list>
	</constructor-arg>
</bean>

Within the application when a Student is added we also validate the details entered. A simple Student Validator is created and referenced from the configuration XML.

<bean id="studentValidator" class="uk.co.eggsylife.validation.StudentValidator" />

Finally we tell Spring the location of our ValidationMessages message properties file. If the user enter any details incorrectly we can raise an error for the field entered and specify a message code for the error. Spring will then look up that message code from the ValidationMessages.properties file

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
	<property name="basenames">
		<list>
			<value>classpath:ValidationMessages</value>
		</list>
	</property>
	<property name="cacheSeconds">
		<value>60</value>
	</property>
</bean>

The app-config is now completed.

Tiles setup and JSP file

Earlier in the tutorial we referenced the location of the Tile definitions, ‘/WEB-INF/tile-defs/tile-defs.xml’. This file declares all the views the web application uses and is crucial to making Spring JS and partial rendering function correctly.

Firstly we define an overall template that can be be used for any views our application requires. Declaring a template allows you to re-use the styling across multiple views.

<definition name="template.view" template="/WEB-INF/pages/templates/template.jsp">
	<put-attribute name="content" value="/WEB-INF/pages/blank.jsp" />
</definition>

The ‘template.jsp’ file is pretty basic. It simple declares the HTML headers. Each time we change the ‘content’ of this Tile definition it will continue to be surrounded by the markup on the template.jsp.

<html>
        <head>
                <script type="text/javascript" src="<c:url value="/resources/dojo/dojo.js" />"> </script>
                <script type="text/javascript" src="<c:url value="/resources/spring/Spring.js" />"> </script>
                <script type="text/javascript" src="<c:url value="/resources/spring/Spring-Dojo.js" />"> </script>
                <link type="text/css" rel="stylesheet" href="<c:url value='/resources/dijit/themes/tundra/tundra.css' />" />
 
                <title>Spring-JS Edit Dialog and Partial JS Example</title>
 
        </head>
 
        <body class="tundra">
 
                <p>Spring Edit Dialog and Partial Content Update Tutorial</p>
 
                <tiles:insertAttribute name="content" />
        </body>
</html>

This means that every page will have the title set as above and every page will have the ‘Spring Edit…..’ paragraph present. Also note we are including the various Spring required Javascript files. By default they are located in the /resources/ folder of the web application. They are required in order to make Spring-JS Ajax functions work.

In this example I have also included the Dojo Tundra theme to improve the look and feel of the sample application but this is by no means required.

The tutorial only has one screen which lists students and should look similar to figure 1.

Figure 1

This screen simply lists the students and provides a link for the user to add a new student. When a new student is added we don’t navigate away from the page we simply append the student to the bottom of the list.

<definition name="students.view" extends="template.view">
	<put-attribute name="content" value="studentsList.view" />
</definition>
 
<definition name="studentsList.view" template="/WEB-INF/pages/students.jsp">
	<put-attribute name="studentsList" value="/WEB-INF/pages/studentList.jsp" />
	<put-attribute name="studentEditDialog" value="/WEB-INF/pages/util/dialogClose.jsp" />
</definition>

We firstly declare the overall ‘students.view’ which extends our default template as mentioned earlier. This view is actually a template itself and requires two entries – a list of students and a student edit dialog. The ‘students.jsp’ file is as follows:

<%@ include file="/WEB-INF/pages/include.jsp" %>
 
<tiles:insertAttribute name="studentsList" />
 
<tiles:insertAttribute name="studentEditDialog" />

The ‘students.jsp’ doesn’t contain much other than the inclusion of the two areas of content. ‘studentList’ and ‘studentEditDialog’. First of all lets look at the ‘studentList.jsp’ file which we inject into the ‘studentsList’ attribute.

<%@ include file="/WEB-INF/pages/include.jsp" %>
 
 
<div id="studentsList">
	<table border="1" width="600px"">
		<thead>
			<tr>
				<th width="33%" align="left">
					Student ID
				</th>
				<th width="33%" align="left">
					First name
				</th>
				<th width="33%" align="left"> 
					Last name
				</th>
			</tr>
		</thead>
		<tbody>
			<c:forEach var="student" items="${students}">
				<tr>
					<td>
						${student.studentNumber}
					</td>
					<td>
						${student.firstName}
					</td>
					<td>
						${student.lastName}
					</td>
				</tr>
			</c:forEach>
		</tbody>
	</table>
 
	<a href="<c:url value='/students/edit' />" id="createStudentLink">
		Create new student
	</a>
 
	<script type="text/javascript">
		dojo.addOnLoad(function() {
			Spring.addDecoration(new Spring.AjaxEventDecoration({
				elementId: "createStudentLink",
				event: "onclick",
				popup:true,
				params: {fragments: "studentsList, studentEditDialog"}
			}));
		});
	</script>
 
</div>

The view simply lists each student in a table and provides a link to be able to add students. There are two main things to note on this JSP. Firstly notice that it is wrapped in a ‘DIV’ element with the same id as the tiles attribute defintion, ‘studentsList’. This is crucial to making Spring partial refresh work. Also note the way in which we ‘decorate’ the ‘Create new student’ link with Spring Javascript.

Firstly we declare the ‘dojo.addOnLoad’ function. This means that this piece of Javascript will execute when the page loads. Next we use the ‘Spring.addDecoration’ method to add the Ajax decorations. This function takes a number of parameters. Firstly the ‘elementId’ This is the id of the element that we attach the decoration to. In this case we are attaching the decoration to the ‘Create new student’ link. The event is then specified. We want the Ajax actions to run when the link is clicked so we specify the ‘onclick’ event. Next we set the ‘popup’ variable to ‘true’. This means that whatever the response is we want it rendered as a popup dialog.

The final parameter is ‘fragments’. This identifies which areas of content we want refresh. We state that we want both the ‘studentsList’ and the ‘studentEditDialog’ updated. Notice the names match our tiles attributes and that we wrap the ‘studentsList.jsp’ in a DIV with the id of ‘studentsList’. This way Spring knows how to identify content and replace it.

Now lets look at the ‘studentEditDialog’ content. In this instance we are injecting a utility JSP file that closes any open dialogs. The JSP is basically a bit of Javascript that closes any open Dojo popup dialogs. When first listing the students it is not particularly useful as we haven’t got any open dialogs. However when we save a new student a redirect to the students list view the JSP’s use will become clear.

<!-- This is a utility JSP that closes any Dojo Modal dialogs -->
<script type="text/javscript">
dojo.query(".dijitDialog").forEach(function(element) {
	dijit.byId(element.id).hide();
});
</script>

The last tile definition is the view that contains our full student edit dialog. The dialog allows users to create a new student, asking for the student name and id number.

<definition name="studentsListAndEditDialog.view" extends="studentsList.view">
	<put-attribute name="studentsList" value="/WEB-INF/pages/blank.jsp" />
	<put-attribute name="studentEditDialog" value="/WEB-INF/pages/studentEditDialog.jsp" />
</definition>

The only difference with this definition is the that we switch out the ‘dialogClose.jsp’ with the actual student edit dialog. The student edit dialog is as follows:

<%@ include file="/WEB-INF/pages/include.jsp" %>
 
 
<div id="studentEditDialog">
	<p>Student Edit Dialog</p>
 
	<form:form id="studentForm" modelAttribute="student">
		<table>
			<tr>
				<td>Student number</td>
				<td>
					<form:input path="studentNumber" />
				</td>
			</tr>
			<tr>
				<td>First name</td>
				<td>
					<form:input path="firstName" />
				</td>
			</tr>
			<tr>
				<td align="center" colspan="2" style="color: red; font-size: 0.8em;">
					<form:errors path="firstName" />
				</td>
			</tr>
			<tr>
				<td>Last name</td>
				<td>
					<form:input path="lastName" />
				</td>
			</tr>
			<tr>
				<td align="center" colspan="2" style="color: red; font-size: 0.8em;">
					<form:errors path="lastName" />
				</td>
			</tr>
		</table>
		<input type="submit" id="saveStudentButton" value="Save student" />
	</form:form>
 
	<script type="text/javascript">
		dojo.addOnLoad(function() {
				Spring.addDecoration(new Spring.AjaxEventDecoration({
    				elementId:'saveStudentButton', 
    				event:'onclick',
    				formId:'studentForm',
    				params: {fragments: "studentsList,studentEditDialog"}
    			}));
		});
	</script>
</div>

Figure 2

Again, notice we wrap the content in a DIV element with the same id as our tiles attribute, ‘studentEditDialog’. We then go on to declare a Spring form. For now I won’t go on to discuss the Spring MVC and form bindings. Finally note we attach the Spring decorations again. The only difference is this time we specify a form id and remove the popup attribute. We attach the code to the ‘Save student’ button which is the submit button for the ‘studentForm’. This means that we want our Ajax events to be actioned when the form is submitted.

That concludes our view definitions. The tiles-defs.xml, students.jsp, studentsList.jsp, dialogClose.jsp and studentEditDialog.jsp.

Java Controllers

The tutorial only has one controller. The ‘StudentController’ handles the three primary functions of the application. It handles the showing of the students list (GET), the showing of the edit dialog (GET) and the adding of a student (POST).

The list of students is handled by the ‘showStudentsList’ method.

private static final String STUDENTS_VIEW_KEY = "students.view";
 
@Autowired
protected ArrayList<Student> students = null
 
 
@RequestMapping(value="/students", method=RequestMethod.GET)
public String showStudentsList(ModelMap modelMap) {
	modelMap.put("students", students);
	return STUDENTS_VIEW_KEY;
}

It simply adds our list of students to the view and returns the ‘students.view’ tile definition. The list of students is Autowired from our Spring app-config file as defined earlier. It is wired to handle the URL ‘/students’.

Secondly there is the ‘showStudentEditForm’ method. This handles the URL ‘/students/edit’ and is called when the user clicks the ‘Create new student’ link.

 
private static final String STUDENT_EDIT_DIALOG_VIEW_KEY = "studentsListAndEditDialog.view";
 
@RequestMapping(value="/students/edit", method=RequestMethod.GET)
public String showStudentEditForm(ModelMap modelMap) {
 
	// Object class will be used as our
	// form backing object
	Student student = new Student();
	modelMap.addAttribute("student", student);
 
 
	return STUDENT_EDIT_DIALOG_VIEW_KEY;
}

It returns the ‘studentsListAndEditDialog.view’ and adds a new ‘Student’ object to the view for our form. This object is used as the form backing object. The Student object is a POJO and will be seen later. Finally we have the ‘saveStudentEdit’ method that is actioned when the form is submitted. If the form is submitted without errors then it simply returns the same view as the listing of the students. If the user submits the form and it contains errors then it returns the edit form view with details of the error.

 
@Autowired
protected StudentValidator studentValidator = null;
 
@RequestMapping(value="/students/edit", method=RequestMethod.POST)
public String saveStudentEdit(@ModelAttribute Student student, BindingResult errors, ModelMap modelMap) {
 
	studentValidator.validate(student, errors);
 
	if( errors.hasErrors() ) {
		return STUDENT_EDIT_DIALOG_VIEW_KEY;
	}
	else {
		students.add(student);
 
		modelMap.put("students", students);
 
		return STUDENTS_VIEW_KEY;
	}	
}

Notice if the form doesn’t have errors we add the student object back into the collection of students and update the list of students in the view. This is important so that the list of students is updated with the student that has just been added. The utility JSP that closes any open Dojo modal dialogs now comes into full use as it makes sure that the edit student dialog is closed after a student has been successfully added. The method responds to the POST request method so it is actioned when our form is ‘POSTED’. The complete StudentController includes all the above methods.

The Validator and Student POJO

To wrap things up the final two Java classes the application uses is the StudentValidator and the POJO Student object.

The validator simply checks that the user has entered both a first name and last name. The Student object encapsulates items a student has.

public class StudentValidator implements Validator {
 
	/* (non-Javadoc)
	 * @see org.springframework.validation.Validator#supports(java.lang.Class)
	 */
	@Override
	public boolean supports(Class<?> clazz) {
		return Student.class.equals(clazz);
	}
 
	/* (non-Javadoc)
	 * @see org.springframework.validation.Validator#validate(java.lang.Object, org.springframework.validation.Errors)
	 */
	@Override
	public void validate(Object obj, Errors errors) {
		Student student = (Student)obj;
 
		if( student.getFirstName() == null || student.getFirstName().length() == 0 ) {
			errors.rejectValue("firstName", "student.first.name.empty");
		}
 
		if( student.getLastName() == null || student.getLastName().length() == 0 ) {
			errors.rejectValue("lastName", "student.last.name.empty");
		}
	}
 
}
public class Student {
 
	private Long studentNumber = null;
	private String firstName = null;
	private String lastName = null;
 
 
	public Long getStudentNumber() {
		return studentNumber;
	}
	public void setStudentNumber(Long studentNumber) {
		this.studentNumber = studentNumber;
	}
 
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
 
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
}

Conclusion

That should have gave you a complete example on how to use Spring-JS alongside Spring MVC and perform partial refresh of the content. The key to understanding the tutorial is understanding the tie between between the tiles defintions, the identified DIV elements and the usage of Javascript to link the two together.

The project can be downloaded as a Zip from GitHub. For those familiar with Git you can also get the project from the Git Repository under the URL ‘git://github.com/eggsy84/SpringPopupRefreshList.git’. If anyone would like to comment or have anything to contribute to the codebase please let me know.

11 thoughts on “Spring JS – Ajax Popup with list refresh

  1. if i use the below template, and i need only studentEditDialog to be refreshed, i tried the params: {fragments: “studentEditDialog”} but its retriving the entire page

    <!-- -->

  2. hi again,
    when i want to save the student information into db it stored as sign question i.e ??????
    while i set table to accept utf-8 data and set web.xml and set jsp page and other part that require be set to utf.
    please help me.
    thanks.

  3. Pingback: dojo nyc
  4. Eggsy,

    This was a very informative article that helped tremendously with a Spring app that I’ve been working on. As you mentioned, documentation is very limited with regards to Spring AJAX and this particular use case. Thanks for the article!

  5. @admin
    Hi again Eggsy,
    I think my problem compiling was related to the @Override annotations in StudentValidator. Since Object doesn’t have those methods, maven is unhappy. When I removed them, things worked.

    In any case, I truly appreciate your work here. It’s great to have a working example of all this, especially including the spring js AddDecoration part.

    Feel free to delete these comments if they detract from your article. Again, thx very much

  6. Hi there,

    The StudentValidator implements a Validator interface and it looks like you are including a different Validator inteface.

    In your ‘imports’ which Validator are you importing?

    Eggsy

  7. Eggsy, I love what you’ve done here. I especially appreciate how you provided everything, instead of leaving out “trivial” items that aren’t exactly trivial for newbies.

    I’m trying to get up to speed on exactly what you’ve tackled here, and I’d really like to try this out. Unfortunately, my environment is still java 1.5, and the build breaks if I simple change the java-version from 1.6 to 1.5. I’m building in eclipse using the m2eclipse plug-in, running the “Maven clean” and “Maven package” Run As… targets. If I leave the java-version in the pom as 1.6, the war builds successfully but won’t deploy. With java-version 1.5, I get the below. Any suggestions for getting this to run with 1.5? Thanks

    [INFO] Scanning for projects…
    [WARNING]
    [WARNING] Some problems were encountered while building the effective model for uk.co:eggsylife:war:1.0.0-BUILD-SNAPSHOT
    [WARNING] ‘build.plugins.plugin.version’ for org.apache.maven.plugins:maven-compiler-plugin is missing. @ line 165, column 12
    [WARNING] ‘build.plugins.plugin.version’ for org.apache.maven.plugins:maven-surefire-plugin is missing. @ line 225, column 12
    [WARNING] ‘build.plugins.plugin.version’ for org.apache.maven.plugins:maven-war-plugin is missing. @ line 173, column 12
    [WARNING]
    [WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
    [WARNING]
    [WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
    [WARNING]
    [INFO]
    [INFO] ————————————————————————
    [INFO] Building PopupRefreshList 1.0.0-BUILD-SNAPSHOT
    [INFO] ————————————————————————
    [INFO]
    [INFO] — aspectj-maven-plugin:1.2:compile (default) @ eggsylife —
    [ERROR] The method supports(Class) of type StudentValidator must override a superclass method
    [ERROR] The method validate(Object, Errors) of type StudentValidator must override a superclass method

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>