It’s somewhat difficult to find examples of the autocomplete ComboBox that the Ext library provides, so I’ll add another one to the mix in the hopes that it makes it easier for future implementers to find.
First, let’s look at the code you need. The Ext stylesheet and the ext-all.js library. Then you’ll need your own, custom interaction code. My naming convention is to start with interaction and then the page to which the code applies.
<link href="css/ext-all.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="js/ext-all.js"></script>
<script type="text/javascript" src="js/interaction.example.js"></script>
This article is going to focus on the HTTPProxy code for the autocomplete feature. The one argument you need is URL, and it value will be the name of the file that is actually going to perform the query and return the results. This code is simply creating a connection to a page that will be used when the user types in a search string.
In the example I’m pulling from, I’m searching against a list of facilities for the company.
facilityProxy = new Ext.data.HttpProxy({url: 'liveQueries/facilities.cfm'});
When the user types in a search string, Ext will then use the HTTPProxy to call facilities.cfm with a URL variable named query that contains the search string. Therefore, if the user typed in ‘PHIL’, the proxy URL would be liveQueries/facilities.cfm?query=PHIL.
Now let’s look at the facilities.cfm code. First, we have to capture the query variable being passed to the page by Ext, which can be done simply with a <cfparam> tag. Then we execute our query. Once we have the resultset, we’ll need to serialize it. I like JSON serialization, so I used the CFJSON code from Thomas Messier, Jehiah Czebotar, and others.
<cfsetting enablecfoutputonly="true">
<cfparam name="query" default="">
<cfquery name="facilities" datasource="#datasource_name#">
select unique facility_no, facility_legal_name
from chg_facility
where (REGEXP_LIKE(facility_no,'#query#','i') OR REGEXP_LIKE(facility_legal_name,'#query#','i'))
order by facility_no asc
</cfquery>
<cfscript>
jsonBean = createobject("component","webapps.charm.model.ajax.JSON");
jsonEncodedCriteria = jsonBean.encode(data=facilities, queryFormat="array");
writeOutput(jsonEncodedCriteria);
</cfscript>
<cfsetting enablecfoutputonly="false">
Ok, so now we’ve got a JSON-serialized query. What do we do with it? Well, Ext just happens to have a built-in JSON reader. Just create a new JsonReader object, tell it what node contains the data (in our case, the node name is data) and optionally provide a totalProperty argument that contains the total number of records returned.
You then provide a defintion of what a single record of data consist. You can define a seperate object called a Record….
facilityRecord = Ext.data.Record.create([
{name: 'facility_no', type: 'string'},
{name: 'facility_legal_name', type: 'string'}
]);
facilityReader = new Ext.data.JsonReader({
root: "data",
totalProperty: "recordcount"
}, facilityRecord);
Or just do it inline if the record is simple enough.
facilityReader = new Ext.data.JsonReader({
root: "data",
totalProperty: "recordcount"
}, [
{name: 'facility_no', type: 'string'},
{name: 'facility_legal_name', type: 'string'}
]);
Alright, so we’ve got a proxy object to facilities.cfm that will perform the query on the user’s search string and return JSON-serialized data. We’ve defined the structure of each record, and use a built-in JSON reader to parse the results.
Lastly, we need to populate a data Store with the deserialized data set that we’ve retrieved. We simply provide it with the name of the proxy we’ll be using and which reader it should use to deserialize the data.
facilityStore = new Ext.data.Store({
proxy: facilityProxy,
reader: facilityReader
});
You can also define each element inline instead of creating a separate variables for each object. Here’s an example:
new Ext.data.Store({
proxy: new Ext.data.HttpProxy({url: 'liveQueries/facilities.cfm'}),
reader: new Ext.data.JsonReader({
root: "data",
totalProperty: "recordcount"
}, [
{name: 'facility_no', type: 'string'},
{name: 'facility_legal_name', type: 'string'}
])
})
Now that’s we’ve got some interaction code running, let’s start creating the actual ComboBox. Create a simple HTML file and place an input element on the page with a unique name.
<input type="text" size="20" id="facilitySearchField">
Then, back in your interaction code, let’s create a ComboBox instance and tell it to use the data store that we’ve already defined.
var search = new Ext.form.ComboBox({
store: facilityStore,
minChars:2,
itemSelector: 'div.search-item',
tpl: new Ext.XTemplate(
'<tpl for="."><div class="search-item">',
'{facility_no} - {facility_legal_name}',
'</div></tpl>'
),
onSelect: function(record){
// What you want to happen when the enter selects a record (or hit the ENTER key)
// Example (redirect to another page):
// document.location.href = 'showFacilityDetails.cfm?facilitySelected&fid=' + record.data.facility_no;
}
});
// Apply the comboBox to the <input> element in our HTML page.
search.applyTo('facilitySearchField');
Summary
HTML Code (example.htm)
<html>
<head>
<link href="css/ext-all.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="js/ext-all.js"></script>
<script type="text/javascript" src="js/interaction.example.js"></script>
</head>
<body>
<input type="text" size="20" id="facilitySearchField">
</body>
</html>
Javascript Code (interaction.example.js)
facilityProxy = new Ext.data.HttpProxy({url: 'liveQueries/facilities.cfm'});
facilityRecord = Ext.data.Record.create([
{name: 'facility_no', type: 'string'},
{name: 'facility_legal_name', type: 'string'}
]);
facilityReader = new Ext.data.JsonReader({
root: "data",
totalProperty: "recordcount"
}, facilityRecord);
facilityStore = new Ext.data.Store({
proxy: facilityProxy,
reader: facilityReader
});
var search = new Ext.form.ComboBox({
store: facilityStore,
minChars:2,
itemSelector: 'div.search-item',
tpl: new Ext.XTemplate(
'<tpl for="."><div class="search-item">',
'{facility_no} - {facility_legal_name}',
'</div></tpl>'
),
onSelect: function(record){ }
});
search.applyTo('facilitySearchField');
ColdFusion Code (facilities.cfm)
<cfsetting enablecfoutputonly="true">
<cfparam name="query" default="">
<cfquery name="facilities" datasource="#datasource_name#">
// Perform search based on user's search string (query parameter)
</cfquery>
<cfscript>
jsonBean = createobject("component","webapps.model.ajax.JSON");
jsonEncodedCriteria = jsonBean.encode(data=facilities, queryFormat="array");
writeOutput(jsonEncodedCriteria);
</cfscript>
<cfsetting enablecfoutputonly="false">