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.
How to use
TextboxList is essentially very easy to use, but is extremely configurable and extensible. Let’s review some sample usage scenarios:
$('#form_tags_input').textboxlist();
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 TextboxList1. 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:
$('#form_tags_input').textboxlist({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 method2.
There’s TextboxListBit class deals with the creation, focusing, blurring, removal and display of the bits, and communicates 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'], // ... ]);
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.
$('#form_tags_input_4').textboxlist({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.
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 class3encodeA function that turns an array into the string that is sent along with the form. The default takes the values, filters out commas and comma-separes them. Tip: you can use JSON here (JSON.stringify)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. Tip: you can use JSON here (JSON.parse)
Events
Events are managed like this:
t.addEvent('focus', fn); // bind focus event to fn t.removeEvent('focus', fn); // remove focus event t.fireEvent('focus', fn); // fire focus event (advanced use only)
This is an extension I made for jQuery to resemble MooTools events management. The main reason for this is that TextboxListBit classes communicate with TextboxList through an internal layer of events, which means a standard single-callback system is not enough.
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.getOptionsRetrieves the current set options for the instance.getContainerRetrieves the container element, which is usually<div class="textboxlist">.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.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
- Autocomplete adding with click bugs
- Unique indexes bugs on IE (which lacked native array.indexOf)
- Bugs with how options were being extended
- 0.3: width calculations for growing inputs corrected.
- 0.4
- [FEATURE] Autocompletion with on-demand server querying
- [ENHANCEMENT] All classes moved to $. to avoid global namespace pollution.
- [FEATURE] Easier jQuery-friendly initialization
- [BUGFIX]
GrowingInputnow works in noConflict mode - [BUGFIX] Fix for
GrowingInputto handle special characters and correctly calculate the input length. - [BUGFIX] Fix for support of multiple addKeys
- [BUGFIX] Fix for focus problem when TextboxList gains focus through focusing an editable input
- [BUGFIX] Autocomplete search term is now trimmed (thanks Mike Feng)
- [BUGFIX] Fix for the .max option
- 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 [↩]
