Autocomplete

This article is also available in the following languages:
By gwoo
The AutocompleteComponent originally submitted by Nate to CakeForge. With a nice intro at
http://cakebaker.42dh.com/2006/06/06/autocompletion-the-easy-way/ The full component and some sample controller and view code is here.

Controller Class:

<?php 
var $components = array('Autocomplete');
var 
$helpers = array('Html''Javascript''Ajax');
?>

View Template:


<?php echo $ajax->autoComplete('Company/name'); ?>

-----------------------------------------------------------

Component Class:

<?php 
<?php
/* SVN FILE: $Id: autocomplete.php 2932 2006-05-23 04:25:29Z nate $ */

/**
 * Automagically handles requests for autocomplete fields
 *
 * CakePHP :  Rapid Development Framework <http://www.cakephp.org/>
 * Copyright (c)    2006, Cake Software Foundation, Inc.
 *                                1785 E. Sahara Avenue, Suite 490-204
 *                                Las Vegas, Nevada 89104
 *
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 *
 * @filesource
 * @copyright        Copyright (c) 2006, Cake Software Foundation, Inc.
 * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP Project
 * @package            cake
 * @subpackage        cake.cake.libs.controller.components
 * @since            CakePHP v 0.10.4.1076
 * @version            $Revision: 2932 $
 * @modifiedby        $LastChangedBy: nate $
 * @lastmodified    $Date: 2006-05-23 00:25:29 -0400 (Tue, 23 May 2006) $
 * @license            http://www.opensource.org/licenses/mit-license.php The MIT License
 */

/**
 * Autocomplete Handler
 *
 * @package        cake
 * @subpackage    cake.cake.libs.controller.components
 *
 */
class AutocompleteComponent extends Object {

    var 
$layout 'ajax';

    var 
$enabled true;

    var 
$components = array('RequestHandler');

    var 
$handles = array();

/**
 * Startup
 *
 * @param object A reference to the controller
 * @return null
 */
    
function startup(&$controller) {

        if (!
$this->enabled || !$this->RequestHandler->isAjax() || !$this->RequestHandler->isPost()) {
            return 
true;
        }

        
$data $controller->data;
        if (empty(
$data) || count($data) != 1) {
            return 
false;
        }

        list(
$model) = array_keys($data);
        if (!
is_array($data[$model]) || count($data[$model]) != || !is_object($controller->{$model})) {
            return 
false;
        }

        list(
$field) = array_keys($data[$model]);
        
$conditions = array();

        if (!empty(
$this->handles)) {

            
$handled false;
            
$fields = array();

            foreach (
$this->handles as $key => $val) {
                if (
is_int($key)) {
                    
$key $val;
                    
$val = array();
                }
                if (
$key == $model.'.'.$field || $key == $field || $key == $model.'.*') {
                    
$handled true;
                    
$conditions $val;
                    break;
                }
            }
            if (!
$handled) {
                return 
true;
            }
        }

        
$base = array($model.'.'.$field => 'LIKE %'.$data[$model][$field].'%');
        if (!empty(
$conditions)) {
            
$conditions = array($base$conditions);
        } else {
            
$conditions $base;
        }

        
$results $controller->{$model}->findAll($conditions);

        if (
is_array($results) && !empty($results)) {
            
e("<ul>\n");
            foreach (
$results as $rec) {
                if (isset(
$rec[$model][$field])) {
                    
e("\t<li>".$rec[$model][$field]."</li>\n");
                }
            }
            
e("</ul>\n");
        }
        exit();
    }
}

?>
?>

Comments

  • Posted 12/17/10 03:48:24 AM
    Hi, I'm trying to understand how to make this component work in CakePHP 1.3 (i took the github updated version, which has a few lines changed)...
    I managed to make autoComplete AjaxHelper's method work, but not this...
    I put the script.aculo.us and prototype .js files in the webroot/js dir including them in the header of the default layout file, set the $helpers and $components vars in the controller, and added the appropriate $ajax->autoComplete('Model.field'); in my view file, but nothing shows up: just a grey line under the field.
    I tried to write a couple of echos into the component, and it seems to load only when the page is called, exiting at
    if (!$this->enabled || !$this->RequestHandler->isAjax() || !$this->RequestHandler->isPost()) {
    return true;
    }

    btw, I don't understand the differences and/or improvements that this component brings with it, compared to the method built into the core.
    thank you :)
  • Posted 03/02/10 03:12:54 PM
    No matter what I do, I get NIL response. My other basic ajax requests work. Is this thing stable? I have cakephp 1.2. What other options are there out there for autocomplete that actually work?
  • Posted 03/01/10 10:36:21 AM
    I have a employee dropdown list-- when an employee is selected and clicked next
    In the next page it shud display the selected empolyee and his department and salary which are present in the users table.

    How do i do it..please guide me.
  • Posted 03/01/10 10:36:13 AM
    ada
  • Posted 09/22/09 11:13:03 AM
    I just blindly downloaded the component, set it up and got the blank screen o death, but just noticed that code above has two sets of tags.

    Oh and +1 for Adriano Varoli Piazza's post - worked well :)
  • Posted 07/28/09 10:21:21 AM
    Hello everybody.

    As Allen and chris pointed out that there is a security issue with the component, I tried to change the Model and field via firebug to show me the user passwords. But it did not work.

    Has the security issue already been bugfixed or am I doing something wrong and the component is still unsafe?
  • Posted 05/14/09 04:23:46 PM
    To get this working for Cake 1.2, the LIKE in the conditions needs to be changed.

    Line 90 should now be:

    $base = array($model.'.'.$field.' LIKE ' => '%'.$data[$model][$field].'%');

    Also in the view don't forget Model.field now instead of Model/field.
    • Posted 10/07/09 08:28:28 AM
      You need also to change line 97 in order to get the component fully functional in cake 1.2


      $results = $controller->{$model}->find('all', array('conditions' => $conditions));


      To get this working for Cake 1.2, the LIKE in the conditions needs to be changed.

      Line 90 should now be:

      $base = array($model.'.'.$field.' LIKE ' => '%'.$data[$model][$field].'%');

      Also in the view don't forget Model.field now instead of Model/field.
  • Posted 12/22/08 02:08:11 PM
    I had the problem where fields from the current model would autocomplete, but others wouldn't. This is what I did:
    - ensure you have the javascript links in your (add them to app/webroot/default.ctp)
    echo $javascript->link('prototype');
    echo $javascript->link('scriptaculous');
    - add the model's name to the $uses var in your controller (I then had to add every model that controller used, bugger)
    - complete the $components and $helpers variables in the controller
    - in the view, add a link such as
    echo $ajax->autoComplete('Model.field');
  • Posted 04/20/08 05:28:44 PM
    Error: Ajax.Autocompleter is not a constructor
    Source File: http://localhost/index.php/products/add/
    Line: 63

    &lt;script type="text/javascript">new Ajax.Autocompleter('ProductName', 'ProductName_autoComplete', '/index.php/products/add/', {});&lt;/script>


    And also nothing happens. I ahve all the helpers, components and manually link to prototype and scriptalicous in head tags.
  • Posted 01/25/08 04:05:45 AM
    I've managed to solve the "autocomplete=off" problem by editing the ajax helper,

    line 450 of ajax.php had:

    $htmlOptions['autocomplete'] = "off";

    Which I changed to on, and it works fine now... I'm not sure this is the correct fix, but it works for me. I think this is possibly a bug?
    • Posted 02/11/08 11:07:16 PM
      I've managed to solve the "autocomplete=off" problem by editing the ajax helper,

      line 450 of ajax.php had:

      $htmlOptions['autocomplete'] = "off";

      Which I changed to on, and it works fine now... I'm not sure this is the correct fix, but it works for me. I think this is possibly a bug?

      The autocomplete="off" attribute of the input field is actually turning off the browsers autocomplete abilities, not the websites. The reason that it is set to off is so that the browsers autocomplete doesn't interfere with the ajax autocomplete. When you say that you've fixed it by altering the framework code I believe all you've really done is turn on the browser autocomplete abilities. I've been playing around with this and find that it works great and I've checked the code and the autocomplete of the input is still set to off.

      Here is the M$(yuck) explanation for reference:
      http://msdn2.microsoft.com/en-us/library/ms533486(VS.85).aspx
  • Posted 12/03/07 12:30:37 PM
    I always encounter serveral javascirpt errors as long as JQuery AND script.acoul.us are loaded.
    These errors prevent autocomplete from working (as well as many other script.acoul.us functions).

    I've solved this problem by just not using JQuery anymore, as sad as this is...

  • Posted 11/13/07 05:17:12 AM
    This components has a lot of problems it give me always the same error ...

    this.element.setAttribute is not a function
    this.element.setAttribute('autocomplete','off');

    controls.js (line 82)

    Can someone explain me how to solve this problem ?
  • Posted 06/30/07 01:26:12 PM
    How do i get for example the name from tags but let it submit the id?
  • Posted 06/29/07 02:28:09 PM
    Please correct me if I am wrong, but isn't there a security issue with this component? A user could technically modify your page locally and point your auto-complete to any field in your database that is in any of the models that are used by the current controller. Therefore, extracting e-mail addresses, usernames, and possibly even passwords.

    CakePHP makes this especially easy, since naming standards allow users to see exactly what your data model looks like.

    Is there something here to prevent it that I am not seeing?
    • Posted 06/30/07 01:42:40 PM
      Yes you are correct.. if i edit the form with firebug, i can enter different fields for the database 0_o this is pretty unsafe.

      Please correct me if I am wrong, but isn't there a security issue with this component? A user could technically modify your page locally and point your auto-complete to any field in your database that is in any of the models that are used by the current controller. Therefore, extracting e-mail addresses, usernames, and possibly even passwords.

      CakePHP makes this especially easy, since naming standards allow users to see exactly what your data model looks like.

      Is there something here to prevent it that I am not seeing?
  • Posted 06/18/07 02:26:20 PM
    It does not seem to work on CakePHP 1.2?

    Is this right? The code it genreates is this:


      <input name="data[Article][title]" type="text" id="ArticleTitle" autocomplete="off" value="" />
      <div id="ArticleTitle_autoComplete" class="auto_complete"></div>
      <script type="text/javascript">new Ajax.Autocompleter('ArticleTitle', 'ArticleTitle_autoComplete', '/mech7/articles/add', {});</script>


    I suppose it is because it says autocomplete=off ?
  • Posted 05/10/07 06:56:42 AM
    It might be better to remove the first '%' on the SQL. So you get more relevant resutls as you type.

    change line 90 to.

    $base = array($model.'.'.$field => 'LIKE '.$data[$model][$field].'%');

  • Posted 11/28/06 12:21:21 PM
    hi,
    where exactly do i have to add or replace the line in the above code if i want to have 2 or more fields -
    in my (similar) case, i want to display lastname, firstname and the client's id e.g. smith, adam [007] - so to offer means to distinguish between two smith adams. -
    thanx 4 your help,
    tom
  • Posted 09/29/06 01:38:12 PM
    Don't forget to

    1. put the js files from http://script.aculo.us in your webroot/js/ folder.

    2. put the following (in this order) between the head tags:
    charsetTag('UTF-8'); ?> link('prototype'); ?> link('scriptaculous.js?load=effects'); ?> link('controls'); ?>
    Very nice!
  • Posted 09/29/06 01:37:57 PM
    You have a couple options.
    1. mysql: CONCAT('first_name','last_name') as name
    2. php:
      foreach ($users as $key=>$user) {
      $user[$key]['User']['fullname'] = $user[$key]['User']['first_name'] . ' ' $user[$key]['User']['last_name'];
      }

    either of those should work.
  • Posted 09/28/06 05:54:24 PM
    Hi gwoo,

    can you also tell how I can show results from two or more fields in the autocomplete box. I want to display full name which consists of first_name and last_name

    Regards,
    Ritesh
  • Posted 11/30/99 12:00:00 AM
    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
  • Posted 11/30/99 12:00:00 AM
    my problem turns out to be that the echo command from the code block above is ommitted:

    charsetTag('UTF-8'); ?> link('prototype'); ?> link('scriptaculous.js?load=effects'); ?> link('controls'); ?>
    just thought that my error might help another Cake novice.
    Al

Comments are closed for articles over a year old