Wednesday, 10 March 2010

Smartgwt autosugget / autocomplete with remote data

Want to embed an autocomplete control in your form. It's easy. Here are the steps you have to follow to get one working. In this example, we will have a control proposing several cities to choose from. On the server side, we will have to define a dao method to filter our collection based on a client criteria:


Server side :

Code snippet taken from AgendaEntryDAOImpl:



public List<City> findCities(final String cityName) {

         List<City> cities = getCities();
         Predicate predicate =  new Predicate(){
           public boolean evaluate(java.lang.Object object){
             City city = (City) object;
             if (city.getName().indexOf(cityName)!=-1)
                   return true;    
             else
                   return false;         
           }      
         };
  
         CollectionUtils.filter(getCities(), predicate); 
         return cities;
 }

 private List<City> getCities() {

         List<City> cities = new ArrayList();

         City city =  new City();
         city.setId((long)1);
         city.setName("London");
         cities.add(city);

         city =  new City();
         city.setId((long)2);
         city.setName("Paris");
         cities.add(city);

  
         city =  new City();
         city.setId((long)3);
         city.setName("Milan");
         cities.add(city);

  
         return cities;
 }


Define your controller, ManageAgendaController  :

public ModelAndView findCities(HttpServletRequest req,
   HttpServletResponse resp) throws Exception {
  
             String name = req.getParameter("name");
             if (name==null)
                   name = "";
             List cities = agendaEntryDAO.findCities(name);         
             Map model = new HashMap();        
             ModelAndView modelAndView = new ModelAndView();
             model.put("jsonResponse", cities);   
             modelAndView.addAllObjects(model);
             View jsonView = new JSONView();
             modelAndView.setView(jsonView);
             return modelAndView;  
 }




On your client, define two form fields, one being your autocomplete field and a hidden hidden input field. The hidden field will be set on selecting a value from the suggested values. You will have to define a handler on selecting a value:


public String getCitiesActionURL(){
  return "manageAgendaController.json?action=findCities";
}


public void loadItems(Reflection... dto) {

.....

final HiddenItem idCity = new HiddenItem("idCity");

  DataSource cityDatasource = getOptionDatasource("/"
    + getCitiesActionURL());
  final ComboBoxItem city = new ComboBoxItem() {
   protected Criteria getPickListFilterCriteria() {
    String name = (String) getValue();
    Criteria criteria = new Criteria("name", name);
    return criteria;
   }
  };  
  
  
  city.addChangeHandler(new com.smartgwt.client.widgets.form.fields.events.ChangeHandler(){   
   public void onChange(com.smartgwt.client.widgets.form.fields.events.ChangeEvent event){
    Object value = event.getValue();
    if (value != null) {
     String idCitystr = (String) value;
     idCity.setValue(idCitystr);
    }
   }
   
   
  });
  
  
  city.setName("city");
  city.setTitle("City");
  city.setDisplayField("name");
  city.setValueField("id");  
  city.setOptionDataSource(cityDatasource); 

........

}


Define the datasource, you must specify the mapping between the deserialized server stream arriving in JSON format and your client record object residing on the client. Hence define 'id' and 'name' attributes.

private DataSource getOptionDatasource(String url) {

    DataSource datasource = new DataSource();
    DataSourceTextField id = new DataSourceTextField("id", "Id");
    id.setPrimaryKey(true);
    DataSourceTextField label = new DataSourceTextField("name", "name");
    datasource.setFields(id, label);
    datasource.setDataFormat(DSDataFormat.JSON);
    datasource.setDataURL(url);
    return datasource;

}


If everything works ok, it should look this:





Download the application source code here

I have deployed a working example to App Engine here

About Me

My Photo