If you are looking for a way to fill a field and perform a live search, in an asynchronous way, look no further.
jQuery autocompleter is a jQuery plugin that performs real-time autocompletion of a text-field.
You need jQuery and the jQuery plugin autocomplete of course.
Let’s suppose we have a text field where the user needs to enter the number of a person id. If the user types 1, all ids starting with 1 will show up. If the user types 12, all ids starting with 12 will show up.
Here is the code I wrote to asynchronously call a method that will perform a JPQL request in a database whenever the user types a digit in the text field.
First, the main JSP, search.jsp :
<%-- jQuery Libraries--%>
<script type="text/javascript" src="ressources/js/jquery-1.4.2.min.js"></script>
<script type="text/javascript" src="ressources/js/jquery-autocomplete/lib/jquery.bgiframe.min.js"></script>
<script type="text/javascript" src="ressources/js/jquery-autocomplete/lib/jquery.ajaxQueue.js"></script>
<script type="text/javascript" src="ressources/js/jquery-autocomplete/lib/thickbox-compressed.js"></script>
<script type="text/javascript" src="ressources/js/jquery-autocomplete/jquery.autocomplete.js"></script>
<link href="ressources/js/jquery-autocomplete/jquery.autocomplete.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
$().ready(function() {
$("#tag").autocomplete('myWebApp/listPersonsId.action', {
minChars: 1,
max: 15,
multiple: false,
autoFill: true
});
});
</script>
...
<td><s:textfield id='tag' name="tagField" label="tag" /></td>
Then the second JSP, tag.jsp, that will hold the content of the list that will show beneath the text field :
tag.jsp : <%@ taglib prefix="s" uri="/struts-tags"%> <s:iterator value="listPersons"> <s:property value="id" escape="false"/> </s:iterator>
The struts mapping file search.xml :
<!-- This action is used to autocomplete the textfield person id -->
<action name="listPersonsId" method="findTag">
<result name="success">/pages/search/tag.jsp</result>
</action>
I have a Person entity bean (with an ID field) and a stateless session bean PersonDAO with a allPersonsById(long PersonId) method :
@SuppressWarnings("unchecked")
public List<Person> allPersonsById(long PersonId) {
String param = String.valueOf(PersonId);
param = PersonId + "%";
Query reqPosition = entityManager.createQuery("select p from Person p where TRIM(p.id) like ?1");
reqPosition.setParameter(1, param);
List<Person> listPersons = reqPosition.getResultList();
return listPersons;
}
Pay special attention to the JPQL request. I have to use the TRIM function because the column ID is a number while the parameter is a String.
Different types throw an exception. TRIM avoids that exception.
Finally here is the Struts 2 action, SearchAction.java:
public class SearchAction extends ActionSupport {
//q is a parameter used by the jQuery autocomplete.js script
private String q;
public String getQ() {
return q;
}
public void setQ(String q) {
this.q = q;
}
// This list will be updated every time the user enters a new digit
public List<Person> listPersons;
public List<Person> getListPersons() {
return listPersons;
}
public void setListPersons(List<Person> listPersons) {
this.listPersons = listPersons;
}
public String findTag() throws Exception {
String qUTF8 = "";
if (null !=q ){
try {
qUTF8 = new String(q.getBytes(), "UTF8");
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
}
}
PersonDaoLocal facade = (PersonDaoLocal) ServiceLocator.getInstance().getService("myWebApp/PersonDao/local");
long personId = Long.valueOf(q);;
listPersons = facade.allPersonsById(personId);
return SUCCESS;
}
}
When a user starts typing in the input box, the autocompleter will request myWebApp/listPersonsId.action with a GET parameter named q that contains the current value of the input box.
Check the plugin documentation for more options.