This week I read an interesting article on Solr and autocomplete. It got me thinking about similar behavior with Solr under ColdFusion. Without going into too much detail, a real autocomplete wasn't feasible with the Solr collections ColdFusion creates, but we could do something similar. Instead of providing a list of auto complete options on your search, I'm going to use Ajax to provide a suggestion based on what you type. Here is what I came up with.
First, I created a simple form:
<form method="post">
<cfoutput><input type="text" name="search" id="search" value="#htmlEditFormat(form.search)#"></cfoutput>
<input type="submit" value="Search"><br/>
<span id="suggestion"></span>
</form>
Everything above should make sense except perhaps for the span. The span is an empty place to put my suggestion when it is returned. Below the form I had a simple place to display the results.
<cfif len(form.search)>
<cfsearch collection="cfdocs" criteria="#form.search#" name="results" maxrows="10">
<cfdump var="#results#">
</cfif>
Now let's look at the jQuery. Back on the top of my document I've got this:
$(document).ready(function() {
$("#search").keyup(function() {
var current = $(this).val();
$.getJSON("search.cfc?method=getsuggestion&returnformat=json", {"search":current}, function(res,code) {
res = $.trim(res);
if(res != '') $("#suggestion").html("Consider searching for <b>"+res+"</b>");
else $("#suggestion").html("");
});
});
})
As you type, I grab the current value of the search field. This gets passed to a CFC (displayed below). The CFC will return a suggestion or a blank string. If we actually get a suggestion we format the result and display it in the span. Pretty simple, right? Now let's look at the CFC.
<cfcomponent output="false">
<cffunction name="getSuggestion" access="remote" returnType="string" output="false">
<cfargument name="search" type="string" required="true">
<cfset var status = "">
<cfset var results = "">
<cfsearch collection="cfdocs" criteria="#arguments.search#" maxrows="1" status="status"
suggestions="always" name="results">
<cfif len(trim(status.collatedresult))>
<cfreturn trim(status.collatedresult)>
<cfelse>
<cfreturn "">
</cfif>
</cffunction>
</cfcomponent>
All my component does is handle suggestions. I'd probably have the real search in there as well so my form above could be simpler, but for now this is sufficient. To get a suggestion, I simply do my search, set suggestions="always", and minimize my actual results with maxrows="1". Suggestions are returned in the status key "collatedresult" and sometimes include a space. Therefore I do a trim before possibly returning it. And now that I've written this, I can further simplify my CFC by just returning the trimmed result like so:
<cffunction name="getSuggestion" access="remote" returnType="string" output="false">
<cfargument name="search" type="string" required="true">
<cfset var status = "">
<cfset var results = "">
<cfsearch collection="cfdocs" criteria="#arguments.search#" maxrows="1" status="status"
suggestions="always" name="results">
<cfreturn trim(status.collatedresult)>
</cffunction>
You can see a demo of this by clicking the big button below. Useful? Suggestion - try typing 'cfcd' as it triggers a good suggestion. My search data is the CFML reference - not the complete doc set.
Sorry - this demo is no longer available online.