thecfguy

A Unique Developer

ColdFusion wrapper for jQuery autocomplete.

For one of my project I required autocomplete box. I know coldfusion has its own autocomplete but has lots of limitation. I wanted autocomplete to work like select box of html, display lable of product in list but in backend it will return ID for that product and as usual I just stop at jQuery-ui Autocomplete (I just love jquery) which allow good customization.
This coldfusion wrapper allow you to use jquery autocomplete with coldfusion query variables or loading data remotely.[googlead]single_line[/googlead]

Example:

<cf_autocompletetextFieldName="productName" textFieldValue="" textFieldBind="PRODUCTNAME"idFieldName="productId" idFieldBind = "PRODUCTID"datasource="/cfc/products.cfc?method=getActiveProduct&returnFormat=JSON"fieldList="PRODUCTID,PRODUCTNAME,PRICE"queryParam="product" displayTemplate="<div><img src=""/images/{PRODUCTID}.gif"">{PRODUCTNAME}&nbsp;: {PRICE}</div>" minlength=2 />

Attributes:

AttributeRequired/OptionalDefaultDescription
dataSourceRequired Can contain two type of value
1. URL: Should return query in JSON format
2. Query: Query variables
delayOptional300The delay in milliseconds the Autocomplete waits after a keystroke to activate itself
delayOptional300The delay in milliseconds the Autocomplete waits after a keystroke to activate itself
disabledOptionalfalseDisable autocomplete
displayTemplateRequired Custom display Template
Ex. <div>{ARTID}-{ARTNAME}</div> word srounded in curly braces will replaced with query field value.
fieldListRequired Field list of query. Must be in same order as writtern in query
idFieldNameOptional Specify hidden field name you like to create.
Optional, it will create hidden variable with specified value. Usefull to store ID.
idFieldBindRequired if idFieldName avaialble Query field bind with hidden element
idFieldValueOptional Default value of hidden field.
minLengthOptional The minimum number of characters a user has to type before the Autocomplete activates. Zero is useful for local data with just a few items. Should be increased when there are a lot of items, where a single character would match a few thousand items.
queryParamOptionalqueryURL parameter name passed for remote call.
randNoOptionalRandom number generated by systemAppend randno to id field to avoid conflicts.
textFieldNameRequired Name of text field
textFieldBindRequired Value to be bound with text field. This field value will display in text field once value selected.
textFieldValueRequired Defult text field value.
autocompleteSearchOptional Before a request (source-option) is started, after minLength and delay are met. Can be canceled (return false), then no request will be started and no items suggested.
autocompleteOpenOptional Bind javascript function with autocomplete Triggered when the suggestion menu is opened.
autocompleteFocusOptional Bind javascript function with autocomplete Before focus is moved to an item (not selecting), ui.item refers to the focused item. The default action of focus is to replace the text field's value with the value of the focused item, though only if the focus event was triggered by a keyboard interaction. Canceling this event prevents the value from being updated, but does not prevent the menu item from being focused.
autocompleteSelectOptional Triggered when an item is selected from the menu; ui.item refers to the selected item. The default action of select is to replace the text field's value with the value of the selected item. Canceling this event prevents the value from being updated, but does not prevent the menu from closing.
autocompleteCloseOptional When the list is hidden - doesn't have to occur together with a change.
autocompleteChangeOptional After an item was selected; ui.item refers to the selected item. Always triggered after the close event.

AutoComplete Code:

<!---     Description: ColdFusion wrapper for jQuery autocomplete.    Requirement: jQuery 1.4+, jQuery UI 1.8+, ColdFusion 8.0+    Developer : Pritesh Patel (iSummation Technology Pvt. Ltd) http://www.isummation.com    Version : 1.0    License:     Licensed under the Creative Commons License, Version 2.5 (the "License");     you may not use this file except in compliance with the License.     You may obtain a copy of the License at         http://creativecommons.org/licenses/by-sa/2.5/in/        Unless required by applicable law or agreed to in writing, software     distributed under the License is distributed on an "AS IS" BASIS,     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.     See the License for the specific language governing permissions and     limitations under the License. ---><cfoutput>    <!---Required:         Can contain two type of value        1. URL: Should return query in JSON format        2. Query: Query variables    --->    <cfparam name="attributes.dataSource" default="">    <!--- Optional:        The delay in milliseconds the Autocomplete waits after a keystroke to activate itself      --->     <cfparam name="attributes.delay" default="300">         <!--- Optional:         Disable autocomplete     --->    <cfparam name="attributes.disabled" default="">            <!--- Required:         Custom display Template         Ex. <div>{ARTID}-{ARTNAME}</div> word srounded in curly braces will replaced with query field value.     --->    <cfparam name="attributes.displayTemplate" default="">     <!--- Required:         Field list of query. Must be in same order as writtern in query     --->    <cfparam name="attributes.fieldList" default="">        <!---  Optional:        Specify hidden field name you like to create.         Optional, it will create hidden variable with specified value. Usefull to store ID.    --->    <cfparam name="attributes.idFieldName" default="">        <!--- Required if idFieldName avaialble        Query field bind with hidden element     --->    <cfparam name="attributes.idFieldBind" default="">    <!--- Optional:        Default value of hidden field.     --->    <cfparam name="attributes.idFieldValue" default="">    <!--- Optional:        The minimum number of characters a user has to type before the Autocomplete activates.         Zero is useful for local data with just a few items.         Should be increased when there are a lot of items,         where a single character would match a few thousand items.     --->    <cfparam name="attributes.minLength" default="0">    <!--- Optional:        User typed text as URL varible to filter query      --->    <cfparam name="attributes.queryParam" default="query">    <!--- Optional:        Append randno to id field to avoid conflicts.     --->    <cfparam name="attributes.randNo" default="#randRange(1000,100000000)#">    <!--- Required:        Name of text field     --->    <cfparam name="attributes.textFieldName" default="">    <!--- Required:        Value to be bound with text field. This field value will display in text field once        value selected.     --->    <cfparam name="attributes.textFieldBind" default="">    <!--- Optional:        Defult text field value.     --->    <cfparam name="attributes.textFieldValue" default="">        <!--- Autocomplete event binding --->    <!--- Optional:        Before a request (source-option) is started, after minLength and delay are met.         Can be canceled (return false), then no request will be started and no items suggested.     --->    <cfparam name="attributes.autocompleteSearch" default="">    <!--- Optional:        Bind javascript function with autocomplete        Triggered when the suggestion menu is opened.     --->    <cfparam name="attributes.autocompleteOpen" default="">    <!--- Optional:        Bind javascript function with autocomplete        Before focus is moved to an item (not selecting), ui.item refers to the focused item.         The default action of focus is to replace the text field's value with the value of the focused         item, though only if the focus event was triggered by a keyboard interaction.         Canceling this event prevents the value from being updated, but does not prevent the menu item         from being focused.     --->    <cfparam name="attributes.autocompleteFocus" default="">    <!--- Optional:        Triggered when an item is selected from the menu; ui.item refers to the selected item.         The default action of select is to replace the text field's value with the value of         the selected item. Canceling this event prevents the value from being updated, but does not         prevent the menu from closing.     --->    <cfparam name="attributes.autocompleteSelect" default="">    <!--- Optional:        When the list is hidden - doesn't have to occur together with a change.     --->    <cfparam name="attributes.autocompleteClose" default="">    <!--- Optional:        After an item was selected; ui.item refers to the selected item. Always triggered after the         close event.     --->    <cfparam name="attributes.autocompleteChange" default="">    <cfif thisTag.ExecutionMode is 'start'>        <cfif not len(trim(attributes.displayTemplate))>            <cfthrow message="attribute displayTemplate is required.">        </cfif>        <cfif not len(trim(attributes.fieldList))>            <cfthrow message="attribute fieldList is required.">        </cfif>        <cfif len(trim(attributes.idFieldName))>            <cfif not len(trim(attributes.idFieldBind))>                <cfthrow message="idFieldBind is required when idFieldName specified.">            </cfif>        </cfif>        <cfif not len(trim(attributes.textFieldName))>            <cfthrow message="attribute textFieldName is required.">        </cfif>        <cfif not len(trim(attributes.textFieldBind))>            <cfthrow message="attribute textFieldBind is required.">        </cfif>                <cfsavecontent variable="headerVal">            <cfoutput>            <script type="text/javascript">            //<![cdata[            $(function(){                <cfif isQuery(attributes.dataSource)>                    var data = #serializeJSON(attributes.dataSource)#;                    var ds#attributes.randno# = $.map(data.DATA, function(item) {                    return {                        <cfset getTemplateVar = REMatchNoCase("\{[\s\S]*?\}",attributes.displayTemplate)>                        <cfset attributes.displayTemplate = jsStringFormat(attributes.displayTemplate)>                        <cfloop from="1" to="#arrayLen(getTemplateVar)#" index="index">                            <cfset attributes.displayTemplate = replaceNoCase(attributes.displayTemplate,"#getTemplateVar[index]#","'+ item[#listFindNoCase(attributes.fieldList,replaceList(getTemplateVar[index],"{,}",","))-1#] +'","all")>                        </cfloop>                        label: '#attributes.displayTemplate#',                        value: item[#listFindNoCase(attributes.fieldList,attributes.textFieldBind)-1#]                        <cfset count = 0>                        <cfloop list="#attributes.fieldList#" index="lc">                        ,#lc#:item[#count#]                        <cfset count = count+1>                        </cfloop>                    }});                </cfif>                $("###attributes.textFieldName#_#attributes.randNo#").autocomplete({                    <cfscript>                        if(len(attributes.disabled) and attributes.disabled)                        writeOutput("disabled:true,");                        if(len(attributes.delay) and attributes.delay)                        writeOutput("delay:#val(attributes.delay)#,");                        writeOutput("minLength:#val(attributes.minLength)#,");                        if(len(attributes.idFieldName))                        {                        if(len(attributes.autocompleteselect))                            writeOutput("select: function(event, ui) {ui.item ? $(""###attributes.idFieldName#_#attributes.randNo#"").val(ui.item.#ucase(attributes.idFieldBind)#) : $(""###attributes.idFieldName#_#attributes.randNo#"").val('');#attributes.autocompleteselect#(event,ui)},");                        else                            writeOutput("select: function(event, ui) {ui.item ? $(""###attributes.idFieldName#_#attributes.randNo#"").val(ui.item.#ucase(attributes.idFieldBind)#) : $(""###attributes.idFieldName#_#attributes.randNo#"").val('');},");                                                    }                        else if(len(attributes.autocompleteselect))                            writeOutput("select:#attributes.autocompleteselect#,");                        if(len(attributes.autocompletesearch))                            writeOutput("search:#attributes.autocompletesearch#,");                        if(len(attributes.autocompleteopen))                            writeOutput("open:#attributes.autocompleteopen#,");                        if(len(attributes.autocompletefocus))                            writeOutput("focus:#attributes.autocompletefocus#,");                        if(len(attributes.autocompleteclose))                            writeOutput("close:#attributes.autocompleteclose#,");                        if(len(attributes.autocompletechange))                            writeOutput("change:#attributes.autocompletechange#,");                    </cfscript>                    <cfif isQuery(attributes.dataSource)>                        source:ds#attributes.randno#                    <cfelseif IsSimpleValue(attributes.dataSource)>                    source: function(request,response){                        $.ajax({                            url: "#attributes.dataSource#",                            dataType: "json",                            data: {                                #attributes.queryParam#: request.term                            },                            success: function(data) {                                response($.map(data.DATA, function(item) {                                    return {                                        <cfset getTemplateVar = REMatchNoCase("\{[\s\S]*?\}",attributes.displayTemplate)>                                        <cfset attributes.displayTemplate = jsStringFormat(attributes.displayTemplate)>                                        <cfloop from="1" to="#arrayLen(getTemplateVar)#" index="index">                                            <cfset attributes.displayTemplate = replaceNoCase(attributes.displayTemplate,"#getTemplateVar[index]#","'+ item[#listFindNoCase(attributes.fieldList,replaceList(getTemplateVar[index],"{,}",","))-1#] +'","all")>                                        </cfloop>                                        label: '#attributes.displayTemplate#',                                        value: item[#listFindNoCase(attributes.fieldList,attributes.textFieldBind)-1#]                                        <cfset count = 0>                                        <cfloop list="#attributes.fieldList#" index="lc">                                        ,#lc#:item[#count#]                                        <cfset count = count+1>                                        </cfloop>                                    }                                }))                            }                        })}                    <cfelse>                        <cfthrow message="Invalid attribute value">                    </cfif>                });            });            /*]]>*/         </script>         </cfoutput>        </cfsavecontent>        <cfhtmlhead text="#headerVal#">        <input type="text" name="#attributes.textFieldName#" id="#attributes.textFieldName#_#attributes.randNo#" value="#attributes.textFieldValue#" />        <cfif len(attributes.idFieldName)>        <input type="hidden" name="#attributes.idFieldName#" id="#attributes.idFieldName#_#attributes.randNo#" value="#attributes.idFieldValue#"  />        </cfif>    </cfif></cfoutput>