Our Blog

Let us find tech solutions together

Jan 27

Autocomplete with an Object

By sswinsburg | Comments

 

The Wicket Extensions package provides a neat component called the AutoCompleteTextField.

In a nutshell, this allows you to provide a TextField with a List of Strings and when you start typing, the ones that match the input show up. This is a great component, but consider this scenario:

You have a list of contacts, one of which you want to send an email to. Each person has a unique id and a name. You want to search based on their name, but send the message to their id.

class Person {
  long uuid;
  String displayName;
  String email;
  ...
}

This is not possible with the AutoCompleteTextField, as it uses a list of Strings and will submit whatever is entered in the text field. What you need is to be able to separate the key from the value.

Enter the ObjectAutoCompleteTextField. This is a class from WicketStuff and allows you to provide a List of Objects and tell the AutoCompleteTextField what value should be the displayed value, and what values should be submitted.

Firstly, the markup is the same as a normal text field: <input type="text" wicket:id="toField" />

Now lets build the parts we need:

1. The list of objects:

final List contacts = dao.getContacts();

2. The AutoCompletionChoicesProvider:

AutoCompletionChoicesProvider provider = new AutoCompletionChoicesProvider() {
	private static final long serialVersionUID = 1L;

	public Iterator getChoices(String input) {
		return logic.getMatchingContacts(contacts, input).iterator();
	}
};

This is called whenever the input changes and allows us to get a list of items from our master list that match the input. In this example we already have the list of contacts, so we just need to return an Iterator of the matches for that list. You could use something like this:

public List getMatchingContacts(List contacts, String search) {
	List subList = new ArrayList();

	for(Person p : connections){
		if(StringUtils.startsWithIgnoreCase(p.getDisplayName(), search)) {
			if(subList.size() == Constants.MAX_CONNECTIONS_PER_SEARCH) {
				break;
			}
			subList.add(p);
		}
	}
	return subList;
}

3. The ObjectAutoCompleteRenderer:

ObjectAutoCompleteRenderer renderer = new ObjectAutoCompleteRenderer(){
	private static final long serialVersionUID = 1L;

	protected String getIdValue(Person p) {
		return p.getUuid();
	}
	protected String getTextValue(Person p) {
		return p.getDisplayName();
	}
};

This separates out the key from the value. From the Person class we want to use the uuid as the submitted value and the displayName as the one that shows up in the textfield and we search based on that.

4. Putting it all together is the ObjectAutoCompleteBuilder which takes the provider and sets the renderer.

ObjectAutoCompleteBuilder builder = new ObjectAutoCompleteBuilder(provider);
builder.autoCompleteRenderer(renderer);

5. Finally, we create the ObjectAutoCompleteField from the builder.

ObjectAutoCompleteField autocompleteField = builder.build("toField", new PropertyModel(newMessage, "to"));
final TextField toField = autocompleteField.getSearchTextField();
toField.setRequired(true);
form.add(autocompleteField);

We now have a textfield that allows us to search through a list of items but submit a different value associated with each of those items. autocomplete

Advanced tip: Once we have found an item in the list, it is set into the TextField. If we want to clear the selection, by default the link is a textual [x]. We can override this to be whatever we want, different text, or even an Image. autocomplete_search

To use an icon like in the example above, add something like this to the builder:

builder.searchLinkImage(new ContextRelativeResource("images/cross.png"));

Join the Mystic Team

If articles like this, and technology that we discuss on the blog is interesting to you, let us know