Nate has published a nice component (update 2009-05-27: for CakePHP 1.2, please use the version from GitHub which contains the patch from Mariano Guezuraga) which makes the creation of an input field with Ajax autocompletion very easy. In fact, it is (almost) as easy as creating a simple input field.
What do you have to do? Put the component to your app/controllers/components directory. In your controller you have to include the component with:
var $components = array('Autocomplete');
Also make sure that you have defined the Ajax helper in your controller. I usually add it to the helpers array in my AppController (app/app_controller.php):
var $helpers = array('Html', 'Javascript', 'Ajax');
After that, you can add the autocompleter to your view.
<?php echo $ajax->autocomplete('Company.name'); ?>
One condition must be fullfilled to make this code snippet work: the controller which renders the view must have access to the appropriate model, in our example to the Company model.
That’s it :)
Thanks to Nate for the hint.

Moi j’obtiens l’erreur suivante :
Erreur : Ajax.Autocompleter is not a constructor
Fichier source : http://localhost/cake/index.php/types/
Ligne : 60
Ma ligne 60 :
new Ajax.Autocompleter(’Type_name’, ‘Type_name_autoComplete’, ‘/cake/index.php//types/’, {asynchronous:true, evalScripts:true});
D’ou pourrait vernir le problème ?
Merci
@jf: Hm, I have no idea what could be the problem. My code looks almost identical…
I am sorry, but maybe you will have more luck in the CakePHP google group: http://groups.google.com/group/cake-php
Solution :
You have to include the prototype and script.aculo.us libraries in the
header of your page.
how can I give access of one model to another for this script.
@new cake: Sorry, I don’t understand what you try to accomplish.
hi,
I am trying to use the autocomplete component but not sure where I am making a mistake
==== Here is my controller that access author model ====
===== This is the view /view/authors/auto.thtml
link(’prototype/prototype’);
echo $javascript->link(’scriptaculous/scriptaculous’);
?>
Last Name
autocomplete(’Author/last_name’); ?>
submit(’View Post’)?>
==== Here is the generated form
Last Name
new Ajax.Autocompleter(’AuthorLastName’, ‘AuthorLastName_autoComplete’, ‘/cake/authors/auto’, {});
hi,
I am trying to use the autocomplete component but not sure where I am making a mistake
==== Here is my controller that access author model ====
class AuthorsController extends AppController
{
var $name = ‘Authors’;
var $scaffold;
var $components = array(’Autocomplete’);
var $helpers = array(’Html’, ‘Javascript’, ‘Ajax’);
function auto(){
}
}//endofclass
===== This is the view /view/authors/auto.thtml
php echo $javascript->link(’prototype/prototype’);
php echo $javascript->link(’scriptaculous/scriptaculous’);
form action=”/authors/auto” method=”POST”
Last Name:
php echo $ajax->autocomplete(’Author/last_name’);
php echo $html->submit(’View Post’)
==== Here is the generated form
form action=”/authors/auto” method=”POST”
label>Last Name
div id=”AuthorLastName_autoComplete” class=”auto_complete” /> new Ajax.Autocompleter(’AuthorLastName’, ‘AuthorLastName_autoComplete’, ‘/cake/authors/auto’, {});
@Ritesh Agrawal: Hm, there was a bug in the latest release of CakePHP, so maybe that is the cause for the problem. See https://trac.cakephp.org/ticket/1154 . If that does not fix the problem, please post the code in the google group (it is easier than posting code here *g*).
For me, what made the difference was adding in a link to the controls.js file, so that my app\views\layout\default.html included these four lines:
charset(’UTF-8′) ?>
link(’prototype’) ?>
link(’controls’) ?>
link(’scriptaculous.js?load=effects’) ?>
Refreshed the page and it all worked perfectly. I just need a little CSS to power the dropdown, and I’ll be set! Thanks!
Oops. Am hoping I can use code tags. The four lines should be:
How I do to access all attributtes of other model for I to use your component autocompleting a attribute that not yourself.
Example:
Model A, hasMany B
Model B, belongsTo A (Table b have a_id attribute)
I need autocomplete a attribute different of ‘a_id’ at Controller of Model B.
How I do?
So Thanks,
JWCunha
var $uses = array(’[Model name]‘);
You MUST include this in your controller code for the ajax autocompletion to work.
I am a total noob, and beg some help. I am trying to use this as described, I have the html, javascript, and ajax helpers in my controller. Actually I have them in my controller and in app_controller.php. I have a form in my view that contains only the setup and completion code for the form, a submit, and the snippet from here. The component is installed in the controllers/components dir. When I call the view, I get the form, but it fails silently. when I check the javascript console, I get an Ajax is not defined error. any clues that will help with my ignorance would be very helpful.
Al
@alwhorley: Did you include the prototype and scriptaculous libraries in the header of your page?
yes I have them in in the head section of my layouts/default.thtml. like this:
charsetTag(’UTF-8′); ?>
link(’lib/prototype’); ?>
link(’src/scriptaculous.js?load=effects’); ?>
link(’src/controls’); ?>
CakePHP :
webroot . ‘favicon.ico’;?>” type=”image/x-icon” />
webroot . ‘favicon.ico’;?>” type=”image/x-icon” />
css(’cake.generic’);?>
Oh, and thanks for your response!
@alwhorley: Hm, to me it sounds like the ajax libraries are not loaded. If you look at the source of the generated page, does it look correct?
D’OH, the echo command was missing in my link statements! thanks for the heads up.
@alwhorley: Cool to hear you could solve the problem :)
Hey thanx..
I found your script very useful.
I am new to cake php.. can u please tell me where to find good tutorial to learn developing components for cake php…
I think you are perfect baker ;)
@Abhinav: Have a look at the manual, there is a chapter about writing components: http://manual.cakephp.org/chapter/components
Btw: I am by no means a perfect baker, I make errors as everyone else ;-)
I can’t register myself on bakery.cakephp.org (white screen after “/user/add”) so i make my comment to the autocomplete component here.
I changed line 109 of version 0.4 from
e(”\t”.$element.”\n”);
to
e(”\t”.preg_replace (”/” . preg_quote($data[$model][$field]) . “/i”, “<strong>” . $data[$model][$field] . “</strong>”, $element).”\n”);
i think it’s even a bit cooler like that :)
Cheers,
mazoo
@mazoo: Did you open a ticket for that issue on https://trac.cakephp.org ?
After i saw in the cake php google group that someone else has the same problem with similar setup, i checked it again and it was fixed…
btw: in my earlier comment about autocompletion i forgot to encode the strong tags around the second $data[][].
@mazoo: Ok, I fixed your comment.
I’m trying to make a Live Search work for a phone list and the AutoComplete component looks like it does sort of what I want so I figure this is the place to get some help.
I’ve got the following view code in one of my view classes:
‘view’,
‘url’ => ‘/usefulnumbers/search’,
‘frequency’ => 1,
‘loading’ => “Element.hide(’view’)”,
‘complete’ => “Effect.Appear(’view’)”
);
echo $ajax->observeField(’UsefulnumberSearch’,
$options);
?>
Above that I have my form with the text input element ‘UsefulnumberSearch’.
What I want to happen whenever I type something into that input element is for my controller to call it’s search function and render my search view form inside the ‘view’ div element.
Now whenever I type anything into the input field, the div appears like it should but I get a SQL_Error because for some reason my code is creating a query that’s something like this:
SELECT * FROM usefulnumbers AS Usefulnumber WHERE ‘Usefulnumber’.’search’ LIKE %%
The problem is that search is not a column in the usefulnumbers table and I have no idea why it’s being added to the query.
The input element that ajax observes has the name data['Usefulnumber']['search'] because I made it with the html helper
input(’Usefulnumber/search’,
array(’size’ => ‘40′));
?>
Could that possibly be causing my problem?
Sorry about the length of this comment but I’ve been beating my head against the wall for a while now and any help you could give me would be GREATLY appreciated.
Thanks,
dswingle
crap, that first block of code should start with:
$options = array(
‘update’ => ‘view’,
@dswingle: I think the AutoComplete component expects that your input field is named like the column in which the data are for the autocomplete functionality, i.e. your input field should look like:
input('Usefulnumber/column_name');HTH
Cakebaker, you rock almost as much as Cake itself. Thank you SO much for the help, it definitely put me in the right direction, and, with a little bit of tinkering, I’ve got livesearch working perfectly!
Again, THANKS!
@dswingle: Thanks, I am glad I could help :)
Hi,
thanks for the really nice component! However, I noticed a small problem when it is used in conjunction with the $ajax->observeField. The component seems to handle all ajax requests so $ajax->observeField doesnt return any valid results. Is it possible to make the component handle only the autocomplete requests ?
Thanks!
Vasilis
@Vasilis: I am not sure if it helps in your situation, but you can disable the component by setting $enabled to false.
HTH
Hey there,
very cool component :)
just have a few remarks :
I tried to use it on a big database – good some pretty bad performance hits because of findAll() and LIKE%% .
My solution:
autocomplete_component.php:
line 88: $base = array($model.’.’.$field => ‘LIKE ‘.$data[$model][$field].’%'); ( remove % in front of LIKE as people are expected to enter the first chars of the desired entry. this also makes the queries faster )
line 95: $controller->{$model}->recursion = false;
$results = $controller->{$model}->findAll($conditions, $field, $field.’ ASC’, 15);
remove recursion as we actually need very little data from that model and get only the desired field. also, limit the returned records ( to 15 in my case ) – otherwise, we can get veeeery long lists.
hope that helped someone’s frustration
thanks,
Georgi
@Georgi: Thanks for this tip!
If anyone is interested, here is the CSS Code I found and modified a little so it works with this:
div.auto_complete {
position:absolute;
width:250px;
background-color:white;
border:1px solid #888;
margin:0px;
padding:0px;
}
div.auto_complete ul {
list-style-type:none;
margin:0px;
padding:0px;
}
div.auto_complete ul li.selected { background-color: #ffb;}
div.auto_complete ul li {
list-style-type:none;
display:block;
margin:0;
padding:2px;
height:32px;
cursor:pointer;
}
@Josh: Thanks for sharing this CSS code!
i cant get it to work!
the code the view generates is
new Ajax.Autocompleter('ApplicationCity', 'ApplicationCity_autoComplete', '/applications/search', {});i have checked common things like including JS files, access to model, nothing wrong there
and why does the generated html code have autocomplete=”off” ??
btw should i name the component autocomplete or autoComplete ??
@angrys0ul: Hm, difficult to say what’s wrong. Do you get any errors?
the full code is not visible in the comment, may be its a security feature
i dont get any kind of errors. the form renders normally but just doesnt autocomplete when something is typed
@angrys0ul: You can paste the code to the bin (http://bin.cakephp.org). Do you get a javascript error? (if you are using Firefox then Firebug is a good tool to see such errors)
I’ve got the same problem as angrys0ul, I’m using cake 1.2… There’s a “Ajax is not defined” error, and autocomplete=off. However if you firebug the autocomplete field to “on” everything works perfectly…
@JoeyK: Hm, did you include the prototype and scriptaculous libraries? At least here it works fine with the latest version of Cake 1.2, and autocomplete=off is set, too.
@angrys0ul & JoeyK:
I had the same problem with you guys, and I found out that I loaded a echo $javascript->link(’scriptaculous.js?load=effects’);
I don’t think you should use “load=effects”. I took that part out of my code, and the autocompletion worked fine.
@Reza: Thanks for the hint!
Thanks for the post!
Model A, hasMany B
Model B, belongsTo A (Table b have a_id attribute)
where A is autocomplete form to extract from B.
In relation to post above. If you’re going to extract data from your member model and you cannot use $uses to link to your current model, you can use this patch below:
replace:
if (!is_array($data[$model]) || count($data[$model]) != 1 || !is_object($controller->{$controller->modelClass}->{$model}) || !is_object($controller->{$model})) {
return false;
}
with:
if (!is_array($data[$model]) || count($data[$model]) != 1 || !is_object($controller->{$controller->modelClass}->{$model}) ) {
if(!is_object($controller->{$model})) {
return false;
}
}
if(is_object($controller->{$controller->modelClass}->{$model})) {
$modelObject = $controller->{$controller->modelClass}->{$model};
}
else {
$modelObject = $controller->{$model};
}
replace:
$results = $controller->{$model}->findAll($conditions);
with:
$results = $modelObject->findAll($conditions);
@Frederick: Thanks for your addition, it may be helpful for others!
To make autosuggest faster when using with database, we might,
1. Limit the resultset with the “limit” clause in the query.
2. Index the column that is searched.
Is there any other technique apart from these two?
@Sam: Apart from your points, the patterns Predictive Fetch and Submission Throttling might help.
I made it work with 1.2 rc3:
in the component, change:
$base = array($model.’.’.$field => ‘LIKE %’.$data[$model][$field].’%');
to:
$base = array($model.’.’.$field.’ LIKE’ => ‘%’.$data[$model][$field].’%');
and:
$results = $controller->{$model}->findAll($conditions);
to:
$results = $controller->{$model}->find(’all’, array(’conditions’ => $conditions));
(this last one not necessary, but I guess findAll methods will be deprecated)
Hi! It seems to be a very nice component, but I can’t make it work. I’m using 1.2 and changed the lines as Mariano suggested. I also changed autocomplete(’Event/title’); ?> to autocomplete(’Event.title’); ?>. I’m quite new to cake, so are there some other things I need to change to make it work? I see the input-form, but when I type something in it, nothing happens. Thanks for the help!
@sbeer: Hm, did you add the prototype/script.aculo.us libraries to “app/webroot/js”?
After reading through all the comments, I still can’t seem to get the autocomplete to work. No error messages is given. It just doesn’t work. Anyway, I’ll put the generated code below, please let me know is it suppose to be like this… Thanks.
@KK Kow: Yes, the output looks correct, though I would use autocomplete(’Member.fullName’); instead of autocomplete(’Member/fullName’);
Did you apply the changes to the component mentioned by Mariano? And did you load the prototype/scriptaculous libraries?
Hope that helps!
Hi, I somehow manage to make it work. I read on some other article saying that we need to set debug to 0 in order for the xhtml to work, so what I do is just added the following line on the first line of the startup method.
Of course I also change the line to ‘Member.fullName’.
Another question though, how do I add label for the my input box, I notice there is not label for the input box.
@KK Kow: To add a label you have to use the label() method of the FormHelper: