Autocomplete with Combobox

From Documentation
DocumentationSmall Talks2006DecemberAutocomplete with Combobox
Autocomplete with Combobox

Author
Tom M. Yeh, Potix Corporation
Date
December 13, 2006
Version
Applicable to ZK 2.0 and later.


The Issue

The auto-complete feature is getting popular these days. Here I illustrate how to use the onChanging event to implement it with a combobox.


A Solution

One of the simplest way to implement the auto-complete feature is to listen the onChanging event, and then alter the child components, comboitem, dynamically based on the content that the user is entering.

In the following codes, I assumed we have a dictionary consisting of all possible suggestions that are used to speed up user's entry. In a real application, you might load the suggestions from a database or a Web service.


The Source Codes
    public class AutoComplete extends Combobox {
      public AutoComplete() {
        refresh(""); //init the child comboitems
      }
      public AutoComplete(String value) {
        super(value); //it invokes setValue(), which inits the child comboitems
      }

      public void setValue(String value) {
        super.setValue(value);
        refresh(value); //refresh the child comboitems
      }
      /** Listens what an user is entering.
       */
      public void onChanging(InputEvent evt) {
        refresh(evt.getValue());
      }

      /** Refresh comboitem based on the specified value.
       */
      private void refresh(String val) {
        int j = Arrays.binarySearch(_dict, val);
        if (j < 0) j = -j-1;

        Iterator it = getItems().iterator();
        for (int cnt = 10; --cnt >= 0 && j < _dict.length && _dict[j].startsWith(val); ++j) {
          if (it != null && it.hasNext()) {
            ((Comboitem)it.next()).setLabel(_dict[j]);
          } else {
            it = null;
            new Comboitem(_dict[j]).setParent(this);
          }
        }

        while (it != null && it.hasNext()) {
          it.next();
          it.remove();
        }
      }

      private static String[] _dict = { //alphabetic order
        "abacus", "accuracy", "acuity", "adage", "afar", "after", "apple",
        "bible", "bird", "bingle", "blog",
        "cabane", "cape", "cease", "cedar",
        "dacron", "definable", "defacto", "deluxe",
        "each", "eager", "effect", "efficacy",
        "far", "far from",
        "girl", "gigantean", "giant",
        "home", "honest", "huge",
        "information", "inner",
        "jump", "jungle", "jungle fever",
        "kaka", "kale", "kame",
        "lamella", "lane", "lemma",
        "master", "maxima", "music",
        "nerve", "new", "number",
        "omega", "opera",
        "pea", "peace", "peaceful",
        "rock",
        "sound", "spread", "student", "super",
        "tea", "teacher",
        "unit", "universe",
        "vector", "victory",
        "wake", "wee", "weak",
        "xeme",
        "yea", "yellow",
        "zebra", "zk",
      };
    }


The isChangingBySelectBack Method

ZK 2.2 introduced a new method called isChangingBySelectBack to the org.zkoss.zk.ui.event.InputEvent class. It denotes whether the onChanging event is caused by user's selecting one of the combo items. When implementing auto-complete, it is better not to filter out unmatched suggestions when user presses UP and DOWN keys to select from the list of suggestions. In other words, it is more user friendly if the onChanging method is as follows.

      public void onChanging(InputEvent evt) {
        if (!evt.isChangingBySelectBack())
          refresh(evt.getValue());
      }


Summary

As illustrated, it is easy to provide auto-complete with the onChanging event. Though you have to write some codes, the algorithm to generate the proper list of suggestions can be as sophisticated as you want.





Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.