Yii 1.1: Simple way to use AutoComplete using different ID and Display Value

15 followers

Usually when we use AutoComplete in a project, We need to show "title" or "name" in the list, while when the form is posted, we need some sort of integer ID referring to the selected value. Out of the Box, CJuiAutoComplete widget doesn't provides different display text and post values.

Here's the simplest way to do it:

Step 1: Extend CJuiAutoComplete

Create a new file /protected/extensions/MyAutoComplete.php and put the following content in it:

<?php
Yii::import("zii.widgets.jui.CJuiAutoComplete");
class myAutoComplete extends CJuiAutoComplete
{
 
    /**
     * Run this widget.
     * This method registers necessary javascript and renders the needed HTML code.
     */
    public function run()
    {
        list($name,$id)=$this->resolveNameID();
 
    // Get ID Attribute of actual hidden field containing selected value
    $attr_id = get_class($this->model).'_'.$this->attribute;
 
        if(isset($this->htmlOptions['id']))
            $id=$this->htmlOptions['id'];
        else
            $this->htmlOptions['id']=$id;
 
        if(isset($this->htmlOptions['name']))
            $name=$this->htmlOptions['name'];
 
        if($this->hasModel()) {
            echo CHtml::textField($name,$this->value,$this->htmlOptions);         
      echo CHtml::activeHiddenField($this->model, $this->attribute);
        }else {
            echo //CHtml::textField($name,$this->value,$this->htmlOptions);       
//CHtml::hiddenField($name,$this->value,$this->htmlOptions);          
        }
 
        if($this->sourceUrl!==null)
            $this->options['source']=CHtml::normalizeUrl($this->sourceUrl); 
        else
            $this->options['source']=$this->source;
 
    // Modify Focus Event to show label in text field instead of value
    if (!isset($this->options['focus'])) {
      $this->options['focus'] = 'js:function(event, ui) {
          $("#'.$id.'").val(ui.item.label);
          return false;
        }';    
    }
 
    if (!isset($this->options['select'])) {
      $this->options['select'] = 'js:function(event, ui) {
            $("#'.$id.'").val(ui.item.label);
            $("#'.$attr_id.'").val(ui.item.id);
        }';
    }
 
    $options=CJavaScript::encode($this->options);
    //$options = $this->options;
 
        $js = "jQuery('#{$id}').autocomplete($options);";
 
        $cs = Yii::app()->getClientScript();
        $cs->registerScript(__CLASS__.'#'.$id, $js);
    }
}

Step 2: Add method to return list in Model

  • Open the appropriate Model, for e.g. if your AutoComplete shows a list of Users, Open protected/models/users.php, if it shows products, open up models/products.php
  • Add the following method to your Model
// Important: The Method below must return each record with id, label keys. See how i've wrote the query "title AS label" below.
 
/* Result should be in this format
  array(
    'id'=>4,
    'label'=>'John',
  ),
  array(
    'id'=>3,
    'label'=>'Grace',
  ),
  array(
    'id'=>5,
    'label'=>'Matt',
  ),
 
*/
    public static function usersAutoComplete($name='') {
 
        // Recommended: Secure Way to Write SQL in Yii 
    $sql= 'SELECT id ,title AS label FROM users WHERE title LIKE :name';
        $name = $name.'%';
        return Yii::app()->db->createCommand($sql)->queryAll(true,array(':name'=>$name));
 
        // Not Recommended: Simple Way for those who can't understand the above way.
    // Uncomment the below and comment out above 3 lines 
    /*
    $sql= "SELECT id ,title AS label FROM users WHERE title LIKE '$name%'";
        return Yii::app()->db->createCommand($sql)->queryAll();
    */
 
    }

Step 3: Add autocomplete action to controller

Create an action in your controller to return list of suggestions in JSON Format, as follows:

public function actionUsersAutocomplete() {
        $term = trim($_GET['term']) ;
 
        if($term !='') {
            // Note: Users::usersAutoComplete is the function you created in Step 2
      $users =  Users::usersAutoComplete($term);
            echo CJSON::encode($users);
            Yii::app()->end();
    }
  }

Step 4: Add widget to view

Finally, Open the view file and add the following widget where you need the AutoComplete Text Field. _Notes:_ 1. attribute=>'user_id' property, set this to your actual field name in Database. 2. name=>'user_autocomplete', try to make a habit of naming the autocomplete field ending with _autocomplete or use your own convention.

// Note: ext.MyAutoComplete is equivalent/shortcut to application.extensions.MyAutoComplete
// This means Look for protected/extensions/MyAutoComplete.php file
$this->widget('ext.myAutoComplete', array(
    'model'=>$model,
    'attribute'=>'user_id',
    'name'=>'user_autocomplete',
    'source'=>$this->createUrl('orders/usersAutoComplete'),  // Controller/Action path for action we created in step 4.
    // additional javascript options for the autocomplete plugin
    'options'=>array(
        'minLength'=>'0',
    ),
    'htmlOptions'=>array(
        'style'=>'height:20px;',
    ),        
));

Done!

Now when you post the form, you get the ID of selected value. Let me know if someone is still unable to follow this and i'll be glad to help. Also please comment if you think there's a better and simpler way to do this.

Total 4 comments

#16505 report it
flaho at 2014/02/28 11:59am
Reset id and label on change

I added this :

if (!isset($this->options['change'])) {
  $this->options['change'] = 'js:function(event, ui) {
    if (!ui.item) {
      $("#' . $id . '").val("");
      $("#' . $attr_id . '").val("");
    }
  }';
}
#16010 report it
seventy6ix at 2014/01/09 03:27am
Add function to AccessRules

If you have defined accessRules() in your controller add the newly created function to it like,

array('allow', // allow authenticated user to perform
    'actions' => array('usersAutocomplete'),
    'users' => array('@'),
),
#14653 report it
Alex D. at 2013/09/01 12:21pm
This post should have more "likes" - thank you!

That was VERY helpful - exactly what I needed! Indeed as was mentioned - theres problem with comments on lines 30,31. Don't actually fully understand what should be uncommented and why. But uncommenting line 30 gives good result ))))

#10524 report it
Ravi Bhalodiya at 2012/11/02 06:11am
There is problem with your MyAutoComplete.php file...

Nothing major but problem with your comment...

Leave a comment

Please to leave your comment.

Write new article