Tuesday, December 5, 2006

Autocompleting with Stripes and Scriptaculous

I recently had to implement autocompletion AJAX functionality with script.aculous.us and Stripes. Once again this AJAX functionality was simple to integrate with Stripes. This code will return a list of users to select from after the user types more than two characters.

Here is an example Stripes action that will be responsible for looking up the users and returning a partial page with the unorder list of users. In this example code the autoCompleteText will capture the text that will be autocompleted. A Spring bean will be used to call out to service which will use a Hibernate DAO to query for the user list.

 public class UserLookupAction implements ActionBean {

String autoCompleteText;

UserService userService;
private List users;

public Resolution findUsers(){
this.users = userService.findUsersByAutocompletion(autoCompleteText);
return new ForwardResolution("/pages/useradmin/FindUsers.jsp");
}

@SpringBean
public void setUserService(UserService userService) {
this.userService = userService;
}

public String getAutoCompleteText() {return autoCompleteText;}

public void setAutoCompleteText(String autoCompleteText) {
this.autoCompleteText = autoCompleteText;
}

public List getUsers() {
return users;
}

public void setActionBeanContext(ActionBeanContext actionBeanContext);
public ActionBeanContext getActionBeanContext() {return this.actionBeanContext;}
}

This JSP is responsible for making the AJAX calls to the Stripes action above. The AJAX.Autocompleter code from Scriptaculous does the work when more than two characters are present in the text field named autocomplete. If there are results they are returned in a partial page as an unordered list (more later). An animated gif indicator is used to signal the user that the AJAX call is being made and searching for results. Also, there is a callback method called getSelectionId that is called afterUpdateElement. This will be used to set the selected user id in a hidden field named autocompleteUserId. This will be used when editing the user through another Stripes action (UserEditAction).

 <style type="text/css">
div.autocomplete {
position:absolute;
background-color:white;
border:1px solid #888;
margin:0px;
padding:0px;
}

div.autocomplete ul {
list-style-type:none;
margin:0px;
padding:0px;
}

div.autocomplete ul li.selected { background-color: #ffb;}

div.autocomplete ul li {
list-style-type:none;
display:block;
margin:0;
padding:5px;
cursor:pointer;
border-bottom: 1px solid #cbcbcb;
}
</style>


<%@ taglib prefix="stripes" uri="http://stripes.sourceforge.net/stripes.tld" %>

<stripes:form beanclass="com.meagle.web.stripes.action.useradmin.UserEditAction">
User Name:
<stripes:text size="30" id="autocomplete" name="autoCompleteText"/>

<div id="autocomplete_choices" class="autocomplete"></div>
<script type="text/javascript">

new Ajax.Autocompleter ("autocomplete",
"autocomplete_choices",
"${pageContext.request.contextPath}/useradmin/UserLookup.action?findUsers=",
{minChars: 2, afterUpdateElement : getSelectionId, indicator: 'indicator1'});

function getSelectionId(text, li) {
$('autocompleteUserId').value = li.id;
}
</script>

<stripes:hidden name="userId" id="autocompleteUserId"/>
<stripes:submit name="editUser" class=class="code-quote">"textBox" value="Edit"/>

<span id="indicator1" style="display: none">
<img width=
"14" height="14"
src="${pageContext.request.contextPath}/images/indicator_circle_ball.gif"
alt="Working..." />

</stripes:form>
Finally, this is the partial page that is returned by the UserLookupAction when results are returned. This simply iterates over the User objects from the Stripes action and creates an unorder list that is stylized with the CSS above.

 <%@ taglib prefix="c" uri=<http://java.sun.com/jsp/jstl/core> %>

<ul>
<c:forEach var="user" items="${ actionBean.users}">
<li id="${user.id}">${user.firstName} ${user.lastName}</li>
</c:forEach>

</ul>