jQuery autocomplete Helper

By Gianluca aka "Gemini"
I use jQuery becose is fast and concise Javascript library. My helper, jmycake, use jQuery for AJAX autocomplete.

Requirements:




Helper:


Helper Class:

Download code <?php 
<?php
class JmycakeHelper extends AppHelper {
    var 
$helpers = array('Javascript');
    var 
$output ='';
    
    
/*
     * $idInput = ID dell'input text su cui fare l'autocomplete
     * $modelSearch = Modello/NomeCampo nel quale cercare al stringa inserita nell'input
     * $other = Array che contiene l'id del campo da aggiornare ed il nome del campo da prendere dal db
     * $numResult = Numero di risultati da mostrare nella lista
     * $strlen = Numero di caratteri dopo i quali iniziare le richieste dell'autocomplete
     */
    
function autocomplete($idInput,$modelSearch,$other=null,$numResult=7,$strlen=1) {
        
$fields"";
        
$setBody "";        
        
$search explode("/",$modelSearch);
        if (
is_array($other)) { 
            foreach (
$other As $k => $v) {
                
$fields .= $v.',';
                
$setBody .= "$('#".$k."').val(".$v.");";
            }
        }
        
$fields .= $search[1];

        
$this->output.=$this->Javascript->codeBlock('
            $("#'
.$idInput.'").ready(function(){
                $("#'
.$idInput.'").attr("onkeyup","query_'.$idInput.'(this.value)");
                $("#'
.$idInput.'").attr("autocomplete","off");
                $("#'
.$idInput.'").after("<span id=\"span_'.$idInput.'\" class=\"autocomplete_live\"></span>");
            });
        
            function query_'
.$idInput.'(txt) {
                if(txt.length >= '
.$strlen.') {
                    $.post("'
.$this->webroot.$this->params["controller"].'/autocomplete", {query: txt, fields: "'.$fields.'", search: "'.$search[1].'", model: "'.$search[0].'", numresult: "'.$numResult.'", rand: "'.$idInput.'"}, function(data){
                        $("#span_'
.$idInput.'").html("<ul id=\'ul_'.$idInput.'\' class=\'autocomplete_live\'>"+data+"</ul>");
                        $("#ul_'
.$idInput.'").width($("#'.$idInput.'").width());
                        $("#span_'
.$idInput.'>ul>li>a").keypress(function(e) {       
                            pressedKey = e.charCode || e.keyCode || -1;
                            switch(pressedKey) {
                                case 38://up
                                    position=position-1;
                                    if (position<0) {
                                        position=dimensione-1;
                                    }
                                    $("#span_'
.$idInput.'>ul>li>a").eq(position).focus();
                                    return false;
                                break;
                                
                                case 40://down
                                    position=position+1;
                                    if (position>=dimensione) {position=0;}
                                        $("#span_'
.$idInput.'>ul>li>a").eq(position).focus();
                                        return false;
                                    break;
                            }
                        });                        
                    });    
                }            
            }
            
            $("#'
.$idInput.'").keypress(function(e) {       
                pressedKey = e.charCode || e.keyCode || -1;
                dimensione=$("#span_'
.$idInput.'>ul>li").size();
                switch(pressedKey) {
                    case 38://up
                        $("#span_'
.$idInput.'>ul>li>a").eq($("#span_'.$idInput.'>ul>li").size()-1).focus();
                        position = $("#span_'
.$idInput.'>ul>li").size()-1;
                    break;
                
                    case 40://down
                        $("#span_'
.$idInput.'>ul>li>a").eq(0).focus();
                        position=0;
                    break;
                }
            });
            
            function set_'
.$idInput.'('.$fields.') {
                '
.$setBody.'
                $("#'
.$idInput.'").val('.$search[1].');
                $("#span_'
.$idInput.'").html("");
            }
        '
);
        return 
$this->output;
    }
}
?>
?>

App Controller:



In app_controller.php add this function:

Download code
    function autocomplete() {
        if ($this->RequestHandler->isAjax() && $this->RequestHandler->isPost()) {
            $fields = explode(",",$this->params['form']['fields']);
            $results = $this->{$this->params['form']['model']}->findAll($this->params['form']['search'].' LIKE \'%'.$this->params['form']['query'].'%\'',$fields,$this->params['form']['search'].' ASC',$this->params['form']['numresult']); 
            $this->set('results',$results);
            $this->set('fields',$fields);
            $this->set('model',$this->params['form']['model']);
            $this->set('input_id',$this->params['form']['rand']);
            $this->set('search',$this->params['form']['search']);
            $this->render('autocomplete','ajax','/common/autocomplete');                
        }
    }

Autocomplete view:


And create the common view:

View Template:

Download code
<?php
    
foreach ($results As $k=>$v) {
        
$value='';
        foreach (
$fields As $i =>$j) {
            
$value .= '"'.$v[$model][$j].'",';
        }
        echo 
"<li onclick='set_".$input_id."(".substr($value,0,strlen($value)-1).")'><a href='#'>".$v[$model][$search]."</a></li>";
    }
?>


Save this view in view/common/autocomplete.ctp.

In you controller:


Add my herper in $helper array:

Download code
var $helpers = array('Html','Form','Javascript','Jmycake');


CSS:


Include this CSS style sheet in your layout:

Download code
@CHARSET "UTF-8";
.autocomplete_live {
    background:#F0F0F0 none repeat scroll 0%;
    clear:both;
    cursor:pointer;
    display:block;
    margin:0px;
    padding:0px;
    z-index:9999;
}

.autocomplete_live ul {
    clear:both;
    display:block;
    list-style-type:none;
    margin:0px;
    padding:0px;
    position:absolute;
    width:100%;
}

.autocomplete_live li {
    background:#F0F0F0 none repeat scroll 0%;
    border-bottom:1px solid #C0C0C0;
    display:block;
    height:25px;
    list-style-type:none;
    margin:0px;
    padding:0px;
}


How-to insert autocomplete in you view:



If you have, for example, this view:

View Template:

Download code
<div class="Nation">
    <h2>Nazioni</h2>    
    <?php echo $form->create('Nation', array('action' => 'test')); ?>
        <?php echo $form->input('id',array("type"=>"hidden")); ?>
        <?php echo $form->input('nation'); ?>
        <?php echo $form->input('iso'); ?>
        <?php echo $form->submit('GO'); ?>
    <?php echo $form->end(); ?>
</div>


For add autocomplete input is easy and fast, add this code in you view:

Download code
<?php echo $jmycake->autocomplete('NationNation','Nation/nation',array('NationId'=>'id','NationIso'=>'iso')); ?>


The helper add on input id "NationNation" the autocomplete that make AJAX request on table "Nation" column name "nation" and, when you select the result, the helper set the value of input NationId with the table "id" and the input NationIso with the "iso" value found.

It's possibile to pass other 2 variable on my helper:

  1. $numResult: number of result that show in the view
  2. $strlen: minimum length of the insert text in the html input


It's all!.

Sorry for my english... :(

Comments 647

CakePHP team comments Author comments

Question

1 Security Issue

Does this have same security issue?

See comment for thread at -> (bakery.cake.org)
/articles/view/autocomplete#comment-1059
posted Sun, Apr 20th 2008, 16:24 by Eddie

Login to Submit a Comment