Version 1.5AutoSuggest Widget
API Quick Reference
JavaScript is required to use the quick reference
Overview
The glow.widgets.AutoSuggest is a widget that adds extra functionality to a form input element. As the user types a word it will display a list of possible suggestions for the user to choose from.
Constructing an AutoSuggest widget
You can create an AutoSuggest widget by calling the constructor with a reference to an HTML input element and a data source to be used to create the suggestions. The HTML input element must be of type text and must be accessible via the currently loaded DOM.
new glow.widgets.AutoSuggest( "#inputElementId", // HTML input element to bind the AutoSuggest to myData // refers to a data source
);
Useful options
You can provide options to customise how the widget looks and functions. In particular you are likely to want to specify what should happen when a suggested item is selected by the user, using the onItemSelect option.
myOpts = { onItemSelect: function(e) { this.val(e.selectedItem.name); // Updates the binded HTML input element with the selected value }
} new glow.widgets.AutoSuggest( "#inputElementId", myData, myOpts
);Providing data to AutoSuggest
You must pass data to the AutoSuggest constructor to be used to search against when the user types a word into the inputElement. The most straightforward way to do that is to provide a JSON data object: a simple array of strings or an array of objects.
myData = [ { name: "AliceBlue", hex: "F0F8FF" }, { name: "AntiqueWhite", hex: "FAEBD7" }, { name: "Aqua", hex: "00FFFF" } // etc...
];
If you use an array of strings, then those strings will be what are used as the 'index', the strings used to determine if a match is made when compared to the user input. If you use an array of objects then, by default, the name property is used as the index (or you can specify or create your own index, as shown below).
Using data from a URL
Instead of a JavaScript array you can pass a single string to the AutoSuggest constructor: a URL that refers to a either a static JS file or a server-side process that will return a JSON data object. In order to minimise how many hits your server receives from this widget you control exactly when and how often the data is loaded from that URL, using the loadData() method. For example this would load the data only once, immediately after the widget is constructed:
new glow.widgets.AutoSuggest( myInputElement, "colornames.js", // URL to data myOpts
).loadData(); // load it nowTry it: (type the name of a web-safe colour)
Note that the data is retrieved using XHR so your browser will enforce the "same origin" security policy - the data URL must be on the same server as the webpage displaying it.
Fine control over when data is loaded
If you know you are loading a large or computationally expensive data object, you may not want to load it regardless of whether it is needed or not. A lazier approach would be to only load it only when the user has actually entered a few characters and shown that they definitely need the data. You could accomplish this by putting your loadData() call in a opts.onInputChange handler which checks to see if there is enough input to warrant getting the data.
new glow.widgets.AutoSuggest( myInputElement, "colornames.js", // URL to data { onItemSelect: function(e) { this.val(e.selectedItem.name); }, onInputChange : function(event) { // only hit the server when we have 2 or more chars if (this.val().length < 2) { event.preventDefault(); // prevent any lookups this.hide(); // and tidy up behind ourselves? } else { this.loadData(); this.find(); } } }
)Try it: (type the name of a web-safe colour)
Note that there is a built-in optimisation that means if the exact same URL is loaded several times in a row, the widget will only actually make the request the first time. So in the above example the server request only happens once, even though the user may type many more than 2 characters.
Updating data from URL dynamically
Often, when using a URL as a datasource, the data will only need to be downloaded from the server once. But you might want to download additional or different data after the user has entered some text. You can create a dynamic dataSource by including the special string {input} somewhere in your URL. This string will be replaced by whatever the current url-escaped value of the inputElement is.
To make a dynamic URL refresh itself, you can call the loadData method from inside an onInputChange handler.
Example
new glow.widgets.AutoSuggest( myInputElement, "colornames.js?color={input}", // a dynamic URL { onInputChange : function(event) { this.loadData(); // refresh the data from the URL } }
);Try it: (type the name of a web-safe colour)
Use this technique with caution, it could cause many unnecessary hits to the server as the user is typing.
Dealing with non-JavaScript responses from the server
It may be that the server returns its data as unformatted text. In that case you can provide a parseData option to convert the text of the server response into a usable JavaScript array.
Note: When the you are using an object as the dataSource and you do not specify an index property, the first property needs to be called 'name'. For example:
JSON
[ { name: "Apple Flan" }, { name: "Easy Shortbread" }, { name: "Apple FlapJack" }, { name: "Flambe of Brandied Apple Ice" }
];Here is an example that returns the JSON above, note the structure of the server response and how the parseData function handles it.
Server response
Apple Flan
Easy Shortbread
Apple FlapJack
Flambe of Brandied Apple IceJavaScript
myOpts = { parseData: function(response) { // Create dataSource object to return var dataObject = []; // Get the response from the server, splitting the // response of a multi-lined file into an array var lines = response.text().split("\n"); // For each entry in the array... glow.lang.map(lines, function(line) { // Add a JSON object with the property // 'name' onto the dataSource array dataObject.push({name:line}); }); return dataObject; } }Using a function to generate data
You may want to generate data dynamically on the client-side, based on what the user has entered into the input element. Simply pass a function to the Autosuggest constructor as the dataSource.
Example
new glow.widgets.AutoSuggest( myInputElement, function() { // generate JSON here, possibly based on this.val() if (this.val() == "a") { return [ {name: "allspice"}, {name: "anise"}, {name: "apple-mint"} ]; } else return []; }, myOpts
);Try it: (type the name of a spice)
Displaying the results
When one or more matches are found, each suggestion will be displayed in a list below the input element. You can specify how the result will be displayed using the formatItem option.
Example
myOpts = { formatItem: function(item) { var html = '<div '; html += 'class="swatch" style="background-color:#'+item.hex+'">'; html += '</div>'; html += item.name; return html; }, activeOnShow: false
}
Try it: (type the name of a web-safe colour)
Determining when an item matches
By default, the text entered into the input element is considered a "match" with any data item if the indexed text begins with the input text. For example the color name "LightYellow" would be considered a match (case insensitive) with the input string "light". You can override this behaviour by providing an opts.isMatch function.
Example
myOpts = { isMatch: function(indexedWord, inputWord) { return ( // only try to match when we have more than 1 character inputWord.length > 1 // match anywhere in the word && indexedWord.indexOf(inputWord) > -1 ); }, formatItem: function(item) { // underline the matched bit var pat = new RegExp(glow.lang.trim(this.getValue()), 'i'); return item.name.replace(pat, "<u>$&<"+"/u>"); }
}Try it: (type the name of a web-safe colour)
Changing the appearance of the widget
You can specify how you want your widget to appear by including a theme and an anim option. By default the theme will be "light", and no animation.
Example
myOpts = { theme: "dark", // or "light" anim: "roll" // or "fade"
}Try it: (type the name of a web-safe colour)
Adding word-completion
The opts.complete option activates a feature of AutoSuggest that will display the completed value of the currently active suggestion.
Example
myOpts = { complete: true
}Try it: (type the name of a web-safe colour)
Indexing your data
If the data object you provide is an array of objects, each object with one or more properties (keys and values), you must specify which of those properties will be used to compare with the user input to see if there is a match. The property name you specify will be the "index property." By default, if you don't specify any index property, AutoSuggest will attempt to use a property named "name." Or you can specify a opts.index that will be either a single property name, an array of property names, or a function that will generate index values.
Example
Assuming your data object is equivalent to the following...
[ { name: "Apple Flan", ingredients: ["apples", "brown sugar", "pastry"], chef: "Delia Smith" }, { name: "Easy Shortbread", ingredients: ["butter", "caster sugar", "flour"], chef: "Delia Smith" }, { name: "Apple FlapJack", ingredients: ["oats", "apples", "golden syrup"], chef: "Jamie Oliver" }, { name: "Flambe of Brandied Apple Ice", ingredients: ["apples", "brandy", "golden syrup"], chef: "Heston Blumenthal" } ]; If no index is specified in your options object, then the default name property will be used as the index, if it exists.
myOpts = { onItemSelect: function(e) { this.val(e.selectedItem.name); }, formatItem: function(item) { var html = item.chef + "'s <br />"; html += "<b>" + item.name + "</b><br />"; html += "<small>made with: "+item.ingredients.join(", ")+"</small>"; return html; }, width: 400
}Try it: (type the name of a recipe)
Or you can specify any property name, and AutoSuggest will use that as the index instead.
Example
myOpts = { index: "ingredients"
}Try it: (type the name of an ingredient)
Or you can also specify a series of property names, and AutoSuggest will use all of them as the index.
Example
myOpts = { index: ["chef", "name"]
}Try it: (type the name of a chef or a recipe)
Finally, you can specify a function that will return an array of values to be indexed.
Example
myOpts = { // map each word of the recipe name to the data item index: function(item) { return item.name.split(" "); }
}Try it: (type any word in the name of a recipe)
What happens when a result is selected
When a user selects one of the displayed results, you will likely want some response to occur. By default nothing will happen, but you can specify what you want to happen by creating an opts.onItemSelect handler.
myOpts = { onItemSelect: function(event) { alert(event.selectedItem.name); }
}Try it: (type any word in the name of a recipe)