Thursday, 26 April 2007

YUI Live Search (aka AJAX AutoComplete) - Integration with Struts

Hi!

Well, if you hadn´t had a look at the YUI LiveSearch component (http://developer.yahoo.com/yui/autocomplete/) go for it. It´s worth the effort.

Autocomplete Component and DataSource.

YUI is just a library of AJAX components, so you would need to integrate it with you favourite framework. However, it´s shipped with some javascript libraries that wrap the XMLHttpRequestObject, so you don´t have to use it like that. Instead it uses the concept of DataSource to send queries and retrieve data:

var serverURL = "/search/liveSearch.do"; //service URL
var schema = ["Results","Id","Name", "Description"]; // data mapping format


var dataSource = new YAHOO.widget.DS_XHR(myServer, mySchema);
dataSource.responseType = YAHOO.widget.DS_XHR.TYPE_JSON;
dataSource.queryMatchSubset = true;
dataSource.maxCacheEntries = 50; // component internal cache size.

this datasource must be passed in the autocomplete constructor:

var liveSearchComponent = new YAHOO.widget.AutoComplete("textField","containerId", datasource);

textField: input search text field component.

containerId: div id that will hold the results.

Well, thats basically what you would need to know to create the datasource and the component (along with some configuration steps, have a look at the YUI tutorial).


Search Service.

We can get the results using a search service invoked by a struts action:

public String search(String searchText, int numMaxResults);

Using this service we should get the data following the format specified in the datasource. In this case we need to get the data in JSON (java script object notation) format:

{"Results":
[{"Id" : "1", "Name": "Lou Reed", "Description
": "NYC Man"},
[{"Id" : "2", "Name": "Lou Dylan","Description": "the man!"}]}
 
Service code using the JSONObject:
 
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class SearchServiceImpl implements SearchService {

public String search(String searchText,...) {
//here goes the code to do the search
//once obtained the results must be formatted using json

JSONObject json = new JSONObject();
JSONArray result = new JSONArray();
JSONObject rowOne = new JSONObject();
JSONObject rowTwo = new JSONObject();
try {
rowOne.put("id", "1");
rowOne.put("Name", "Lou Reed");
rowOne.put("Description", "NYC Man");
result.put(rowOne);

rowTwo.put("id", "2");
rowTwo.put("Name", "Lou Dylan");
rowTwo.put("Description", "the man!");
result.put(rowTwo);
json.put("Results", result);
}
catch (JSONException e) {
//umm a checked exception!! :)
//do something!
}
return json.toString();
};

That would be the search service, of course it could be whatever you want, a POJO, a Web Service etc.. the only thing to keep in mind is returning the data using the JSON format (specified in the datasource schema).

JSON Struts Action

It´s almost finished! we only need the controller code, to return the JSON String. In order to that, we need to write a special kind of action. Intead of returning and instance of action mapping, we should get the response object and flush the JSON object to the client:

public ActionForward execute (ActionMapping mapping,...) {

String json = searchService.search(searchText,...);

res.setContentType(TEXT_JAVASCRIPT);res.setHeader("Cache-Control", "no-cache");
PrintWriter pw = res.getWriter();

pw.write(json);pw.close();
return null;

Of course, you could do an abstract JSON Action class, or a helper to reuse it through the application.

1 comment:

RD said...

Excellent post! Helped me a lot! If its ok with you, I would like to send you the sample code. Maybe you can put it up somewhere, for others to download and benefit!

Thank you so very much for such a nice and informative post!

Cheers,
Rohitesh.