TextboxList
TextboxList turns normal textboxes into a widget which can be navigated with the keyboard, effectively turning your input into a “list” of items that can be easily deleted. It comes with an Autocomplete plugin.
Demo
Click here to see it in action.
License
You can use and modify TextboxList freely for any non-commercial use. Otherwise you need to purchase a one-time per-domain license of $20, by clicking on the link on the right.
Browsers support
TextboxList has been tested and is officially supported on IE6, IE7, IE8, Firefox, Safari and Chrome. You may report bugs concerning other browsers, but they’ll get a lower priority.
Size
TextboxList + TextboxList.Autocomplete are only 4.3K minified (YUI) and gzipped.
How to use
TextboxList is essentially very easy to use, but is extremely configurable and extensible. Let’s review some sample usage scenarios:
new TextboxList('form_tags_input');
This turns the <input id="form_tags_input"> into a TextboxList widget. By default, as shown in the demo, the user can add new boxes by pressing enter, write between boxes, delete them with backspace and delete keys. Additionally, a delete button is shown in each of the added items. All these behaviors can be configured, as shown in the sections below.
var t = new TextboxList('form_tags_input'); t.add('Tag 1').add('Tag 2').add('Tag 3');
In this example we call the public add() method of the TextboxList instance to add items from JavaScript.
The anatomy of TextboxList
This section will be useful for those interested in customizing the default behavior of TextboxList, extending the main classes or writing their own plugins.
The parts that constitute a TextboxList widget are called bits. These parts have common characteristics: they can be focused, blurred, deleted, hidden, they are a fragment of the overall value, etc. TextboxList has two essential bits: the editable and the box bit.
Some options involved in the behavior and appearance of the widget are specific to the editable bits, and some are specific to the box bits, which are separate classes from TextboxList[1]. To easily pass them from the main class, you use the bitsOptions property. For example, to disable the delete button in boxes bits, and use the shift key for adding items instead of the enter key:
new TextboxList('form_tags_input', {bitsOptions: { box: {deleteButton: false}, editable: {addKeys: Event.Keys.shift} }});
Knowing this gives you more customization power. If you want to target the blur event of any bit, attach a onBitBlur listener. If you want to target boxes, you can use onBitBoxBlur. You can see a complete list of options and events at the bottom of this page.
The anatomy of a bit
Each bit has a value of the format [id, plaintext, html]. For boxes, this can mean that one that says “John Doe” really passes the value “3″ when making a POST. And it even allows you to customize the content of the box by using a different HTML representation. The id and html, however, are optional, like shown in the first example above. We called add() with just the plain text, and not an id or html, which are the second and third arguments of the method[2].
There’s an abstract TextboxListBit class from which TextboxListBit.Box and TextboxListBit.Editable are inherited. These classes deal with the creation, focusing, blurring, removal and display of the bits, and communicate with the main class by firing events/callbacks. There’re still many tasks that have to be taken care of by the TextboxList class, such as making sure the name of bits doesn’t exceed the value the user specified with the max option.
Autocompletion
Autocompletion is another chapter in the TextboxList story. Again, if you plan to use Autocompletion, it’d be wise to read the sections above.
Autocomplete (like other plugins) is initialized like this:
var t = new TextboxList('input_id', {plugins: {autocomplete: {options}});
You can then access the TextboxList.Autocomplete instance from the plugins property:
var autocomplete = t.plugins['autocomplete']; // autocomplete.someMethod();
The autocompleter plugin is independent of the datasource. In order for autocompletion to be enabled, you have to supply a valid array of would-be bits by calling setValues(). The searches are performed on the bit plain text.
// continues from the last example autocomplete.setValues([ [31, 'Bit Plain Text', 'Bit html', 'Suggestion item html'], // ... ]);
Naturally, you can call that very function with a result from Request.JSON, Request.JSONP, Swift or construct the array from DOM elements.
Autocompletion: querying the server as the user types
The autocomplete can also query the server as the user types. When the user types at least as many characters as specified by the minLength option, a XHR request is performed to the server, which has to respond with a subset of results in JSON.
var t5 = new TextboxList('form_tags_input_4', {unique: true, plugins: {autocomplete: { minLength: 3, queryRemote: true, remote: {url: 'autocomplete2.php'} }}});
Autocompletion: binary search
Binary search is a very efficient searching algorithm which you can use by including the TextboxList.Autocomplete.Binary.js file and passing the method: 'binary' option to the Autocomplete plugin:
new TextboxList('input_id', {plugins: {autocomplete: {method: 'binary'}}});
Only use it under these conditions:
- You have many values to filter
- The values array is sorted alphabetically
- You can afford searching only the beginning of the strings
The method works by first locating the first match of the user input in the values. As an example, if we search for ‘z’ in the demo, it takes linear, standard filtering 62 tries to determine there’re no results. For binary search, it takes 6.
Since binary search was conceived to find a single match, what the filtering method does is look up and down through the array for other matches and come up with a list of suggestions.
Custom styling
Please refer to the comments in TextboxList.css and TextboxList.Autocomplete.css for style customization guidelines.
Extending TextboxList
The core functionality can be extended easily:
var MyTextboxList = new Class({ Extends: TextboxList, // your methods or overrides });
If you wish to extend the Bits, make sure you override the create method:
var MyTextboxList = new Class({ Extends: TextboxList, create: function(klass, value, options){ // ... return new MyTextboxListBit[klass.capitalize()]... } }); MyTextboxListBit = {}; MyTextboxListBit.Box = new Class({ Extends: TextboxListBit.Box, // ... }); MyTextboxListBit.Editable = new Class({ Extends: TextboxListBit.Editable, // ... });
API
Options
prefix(default to ‘textboxlist’) Prefix of the HTML classes of the different parts of the widget.max(defaults to null) If set to a value other than null or false, a maximum number of boxes that can be added.unique(defaults to false) If set to true, an id (or plain text if id not present) of a bit can’t be repeated.uniqueInsensitive(defaults to true) If set to true and an id is not present for a bit, the check for a repeated plain text disregards case.endEditableBit(defaults to true) Whether an editable bit at the end of the widget is added by default.startEditableBit(defaults to true) Whether an editable bit can be added to the left of the first box (ie: beginning of the widget)hideEditableBits(defaults to true) Whether to hide editables bit that are not currently focusedinBetweenEditableBits(defaults to true) Whether to add editable bits between to boxeskeys(defaults to left key and right key) An object consisting of a previous and next key whose values are event codes for moving to previous and next bits.plugins(defaults to {}) An object with maps a plugin name and its options, for initialization. The plugin name is camelcased and capitalized to find the class[3]checkA function that filters out (and prevents the addition of) a bit. For example, if the item is not an email address.encodeA function that turns an array into the string that is sent along with the form. The default takes the values and comma-separes them. Receives all the values of all bits as parameter.decodeDoes the opposite of encode. Used when initializing textboxlist, which tries to read values from the element. The default looks for commas to split the string.
Events
focus: when the widget is focusedblur: when the widget is blurredbitFocus: when a bit is focused. Passes the bit object as parameterbitBlur: when a bit is blurred. Passes the bit object as parameterbitAdd: when a bit is added. Passes the bit object as parameterbitRemove: when a bit is removed. Passes the bit object as parameterbitBoxFocus: when a box bit is focused. Passes the bit object as parameterbitBoxBlur: when a box bit is blurred. Passes the bit object as parameterbitBoxAdd: when a box bit is added. Passes the bit object as parameterbitBoxRemove: when a box bit is removed. Passes the bit object as parameterbitEditableFocus: when a editable bit is focused. Passes the bit object as parameterbitEditableBlur: when a editable bit is blurred. Passes the bit object as parameterbitEditableAdd: when a editable bit is added. Passes the bit object as parameterbitEditableRemove: when a editable bit is removed. Passes the bit object as parameter
Public Methods
create(klass, value, options) Creates a bit of class klass, with value value and options options. Returns the bitfocusRelative(dir, element) Moves the focus to the dir (previous, next) element of the element element, if supplied. Otherwise it uses the current elementfocusLastFocuses the last bitadd(plain, id, html, afterEl) Adds a box bit with value [id, plain, html], and injects it after the last available box, unless afterEl is supplied.getValuesReturns an array with the values from all the box bits.setValues(values) Creates the box bits from the values array.update(values) Updates the input with the values from getValues. This is done for you automagically, and is rarely needed.
Editable Bits Options
Refer to the bit anatomy section to see how to pass these.
tabIndex(defaults to null) Don’t set this option directly. Set the tabindex attribute to the original inputgrows(defaults to true) Whether a GrowingInput instance is created for the inputgrowingOptions(defaults to {}) An options object passed to GrowingInputstopEnter(defaults to true) Whether the event propagation is stopped when enter is pressed. Useful because enter triggers form submissionaddOnBlur(defaults to false) Whether a box is added with the input content when the input is blurred.addKeys(defaults to Event.Keys.enter) A key or array of keys that trigger adding a box with the input content.
Box Bits Options
Refer to the bit anatomy section to see how to pass these.
deleteButton(defaults to true) Whether a delete button is added in the box.
Autocomplete Options
Refer to the binary search section to see how to pass these.
minLength(defaults to 1) Minimum number of characters typed in to trigger search.maxResults(defaults to 10) Maximum number of results to display.insensitive(defaults to true) Whether to perform a case-insensitive searchhighlight(defaults to true) Whether to highlight results.highlightSelector(defaults to null) Optionally, A CSS3 selector to determine on which elements of the autocomplete suggestion to perform highlighting.mouseInteraction(defaults to true) Whether to allow mouse (hovering and clicking) interaction.onlyFromValues(defaults to false) If set to true, the user can only pick values from the suggestions.queryRemote(defaults to false) If set to true, the script attempts to retrieve suggestions from a remote URL, set by the remote option.-
remote(defaults to {}) Options objecturlURL to query by Request.JSON to retrieve the suggestions.param(defaults to ’search’) Name of the parameter in which to send the string to searchextraParamsAn object with extra parameters to send, or a function that returns that object.loadPlaceholderPlaceholder text to display when loading.
method(defaults to ’standard’) Search/highlighting method defined in TextboxList.Autocomplete.Methodsplaceholder(defaults to ‘Type to receive suggestions’) A placeholder text to display. If it evaluates to false, placeholder is not shown or inserted.
Autocomplete Public Methods
Refer to autocompletion section to see how to call these.
setValues(values) Seeds the autocompleter with suggestions from the values array.
Changelog
- 0.1: first release
- 0.2: TextboxList completely rewritten (current)
- 0.3:
- HTML for bits not showing properly fixed
highlightSelectornot working (due to a typo) fixedGrowingInputmissing pad function added (only affected if you customized growing.mini option)- Improved clicking the whole widget behavior
- Other tiny enhancements / cleanup
- 0.4:
checkadded,filterdeprecatedqueryRemoteandremoteadded to Autocompleteencodenow receives all the values of all bits- Fixed but with id 0 translating to null.
autocomplete2.phpadded- Demos updated
- 0.5: fixes a problem with non-remote use of Autocomplete.
- Even though they are separate classes and you can instantiate them from your code, usually you’ll want to use the add or create methods. [↩]
- If we had wanted to add an item with an id 31 and html, we could have done t.add(’Entry’, 31, ‘<img src=”some_entry_image.png” /> Entry’); [↩]
- If you pass plugins: {’some-plugin’: {}} it’ll try to initialize TextboxList.SomePlugin [↩]
