Monday, 14 March 2011

CJuiAutoComplete Custom Listing Example

The CJuiAutoComplete in Yii is great but because it uses the standard interface, there is one thing that cannot be done directly with the Yii control, that is customising the list that is displayed when you type something in. In my last example was a simple list that just displayed the label and selected this when you clicked it (and stored an id number in a hidden field) but in my case, I am searching for church names and there would be lots of duplicates so the name of the church by itself is not enough.
There is an 'undocumented' feature of the jQuery autocomplete (which the Yii control uses) which is mentioned on various forums and which can be used to override the default behaviour. It is called _renderItem and which by default only prints the labels. This needs to be 'manually' linked to the jQuery object since it cannot be joined directly to the CJuiAutoComplete and this uses the Yii function registerScript(). Anyway, this is the code I used (see my earlier example for what all the other controls are):
    $("#churchac").data( "autocomplete" )._renderItem = function( ul, item ) {
 return $( "<li></li>" )
 .data( "item.autocomplete", item )
 .append( "<a>" + item.label + ", " + item.street + ", " + + "</a>" )
 .appendTo( ul );

Most of these names and code I left as per the example because I wasn't totally sure what they were. The only things I changed were the name of the script which is used as a dictionary lookup, the jQuery selector (#churchac) and the line which appends the <a> reference. This by default prints only item.label. In my case, all I did was add some commas and the street and city names. You should retain the <a> tags if you want the arrow keys and such like to work.


I tried to use this recently and it didn't work (cannot set _renderItem on undefined). I don't know what has changed, it is possibly a timing issue in my code, but a workaround is to modify the _renderItem method for ALL instances of autocomplete by re-defining the main definition instead of only the one for this specific instance. You do this by changing line 2 from:

$("#churchac").data( "autocomplete" )._renderItem = function( ul, item ) {
$.ui.autocomplete.prototype._renderItem = function( ul, item ) { 

Note that since I only apply this script in my controller action for one page, it will only affect the autocomplete control(s) on that one page.
Post a Comment