Yii Framework Forum: autocomplete widget for yii-user - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

autocomplete widget for yii-user Rate Topic: -----

#1 User is offline   hermallorn 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 07-December 10
  • Location:lille, france

Posted 08 December 2010 - 06:21 PM

You will find below an autocomplete widget to be added to yii-user (/components).
Everything works fine but as I couldn't figure out the "relation" parameter, this part may need correction.
Enjoy!


<?php
class UWjuiAutoComplete {
/***--------------------------------------------------------------------------------------------------------------------------------------------***/
public $params = array(
'ui-theme'=>'base',
'modelName'=>'',
'optionName'=>'',
'emptyField'=>array(
'label'=>'Not found',
'id'=>'0'),
'relationName'=>'',
'minLength'=>'',
);
/***--------------------------------------------------------------------------------------------------------------------------------------------***/
/*** Widget initialization @return array ***/
public function init() {
return array(
'name'=>__CLASS__,
'label'=>Yii::t('default','jQueryUI autocomplete',array(),__CLASS__),
'fieldType'=>array('INTEGER'),
'params'=>$this->params,
'paramsLabels' => array(
'modelName'=>Yii::t('default','Model Name',array(),__CLASS__),
'optionName'=>Yii::t('default','Lable field name',array(),__CLASS__),
'emptyField'=>Yii::t('default','Empty item name',array(),__CLASS__),
'relationName'=>Yii::t('default','Profile model relation name',array(),__CLASS__),
'minLength'=>Yii::t('default','minimal start research length',array(),__CLASS__),
),
);
}
/***--------------------------------------------------------------------------------------------------------------------------------------------***/
/*** @param $value, @param $model, @param $field_varname, @return string ***/
public function setAttributes($value,$model,$field_varname) {
return $value;
}
/***--------------------------------------------------------------------------------------------------------------------------------------------***/
/*** @param $model - profile model, @param $field - profile fields model item, @return string ***/
public function viewAttribute($model,$field) {
$relation = $model->relations();
if ($this->params['relationName']&&isset($relation[$this->params['relationName']])) {
$m = $model->__get($this->params['relationName']);
} else {
$m = CActiveRecord::model($this->params['modelName'])->findByPk($model->getAttribute($field->varname));
}

if ($m)
return (($this->params['optionName'])?$m->getAttribute($this->params['optionName']):$m->id);
else
return $this->params['emptyField']['label'];
}
/***--------------------------------------------------------------------------------------------------------------------------------------------***/
/*** @param $model - profile model, @param $field - profile fields model item, @param $params - htmlOptions, @return string ***/
public function editAttribute($model,$field,$htmlOptions=array()) {
$list = array();
if ($this->params['emptyField']) $list[]=$this->params['emptyField'];
$models = CActiveRecord::model($this->params['modelName'])->findAll();
foreach ($models as $m)
$list[] = (($this->params['optionName'])?array('label'=>$m->getAttribute($this->params['optionName']),'id'=>$m->id):array('label'=>$m->id,'id'=>$m->id));
if (!isset($htmlOptions['id'])) $htmlOptions['id'] = $field->varname;
$id = $htmlOptions['id'];
/*****/
$relation = $model->relations();
if ($this->params['relationName']&&isset($relation[$this->params['relationName']])) {
$m = $model->__get($this->params['relationName']);
} else {
$m = CActiveRecord::model($this->params['modelName'])->findByPk($model->getAttribute($field->varname));
}

if ($m)
$default_value = (($this->params['optionName'])?$m->getAttribute($this->params['optionName']):$m->id);
else
$default_value = '';
/*****/
$htmlOptions['value'] = $default_value;
$options['source'] = $list;
// $options['source'] = array('aaac1', 'aaac2', 'aaac3');
$options['minLength'] = $this->params['minLength'];
$options['showAnim'] = 'fold';
$options['select'] = "js:function(event, ui) { $('#".get_class($model)."_".$field->varname."').val(ui.item.id);}";
$options=CJavaScript::encode($options);
$basePath=Yii::getPathOfAlias('application.views.asset');
$baseUrl=Yii::app()->getAssetManager()->publish($basePath);
$cs = Yii::app()->getClientScript();
$cs->registerCssFile($baseUrl.'/css/'.$this->params['ui-theme'].'/jquery-ui.css');
$cs->registerScriptFile($baseUrl.'/js/jquery-ui.min.js');
$js = "jQuery('#{$id}').autocomplete({$options});";
$cs->registerScript('Autocomplete'.'#'.$id, $js);
return CHtml::activeTextField($model,$field->varname,$htmlOptions).CHtml::activehiddenField($model,$field->varname);
}
}
0

#2 User is offline   Benn 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 47
  • Joined: 16-January 11
  • Location:Paris

Posted 13 February 2011 - 08:31 PM

Bonjour Hermallorn! :)
Thanks for this widget! I just discovered Yii-user and was just sarting to wonder if it was possible to integrate CjuiAutoComplete to it...
I just tried it out, unfortunately, I get an CException :
The asset "C:\websites\myapp\protected\views\asset" to be published does not exist.
Any idea where that might come from?
Also, I was wondering if you might know how I could get one autocomplete to depend on the previous one in yii-user profile fields (Country -> State)

Thanks a lot!

Cheers
0

#3 User is offline   Benn 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 47
  • Joined: 16-January 11
  • Location:Paris

Posted 14 February 2011 - 07:23 PM

Never mind my first question, I got it working :)
it was simply a matter of replacing

$basePath=Yii::getPathOfAlias('application.views.asset');


by

$basePath = Yii::getPathOfAlias('application.modules.user.views.asset');

0

#4 User is offline   Benn 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 47
  • Joined: 16-January 11
  • Location:Paris

Posted 16 February 2011 - 07:44 PM

Ok, I've almost cracked it :)
I've created a new widget based on UWjuiAutoComplete :
<?php
/**
 * Description of UWjuiAutoCompleteDependent */
class UWjuiAutoCompleteDependent {

    public $params = array(
        'ui-theme' => 'base',
        'modelName' => '',
        'optionName' => '',
        'emptyField' => array(
            'label' => 'Not found',
            'id' => '0'),
        'relationName' => '',
        'parentName' => '',
        'parentFieldName' => '',
        'minLength' => '',
    );
    /*     * *--------------------------------------------------------------------------------------------------------------------------------------------** */
    /*     * * Widget initialization @return array ** */

    public function init() {
        return array(
            'name' => __CLASS__,
            'label' => Yii::t('default', 'jQueryUI autocomplete dependent', array(), __CLASS__),
            'fieldType' => array('INTEGER'),
            'params' => $this->params,
            'paramsLabels' => array(
                'modelName' => Yii::t('default', 'Model Name', array(), __CLASS__),
                'optionName' => Yii::t('default', 'Label field name', array(), __CLASS__),
                'emptyField' => Yii::t('default', 'Empty item name', array(), __CLASS__),
                'relationName' => Yii::t('default', 'Profile model relation name', array(), __CLASS__),
                'parentName' => Yii::t('default', 'Parent name', array(), __CLASS__),
                'parentFieldName' => Yii::t('default', 'Parent field name', array(), __CLASS__),
                'minLength' => Yii::t('default', 'minimal start research length', array(), __CLASS__),
            ),
        );
    }

    /*     * *--------------------------------------------------------------------------------------------------------------------------------------------** */
    /*     * * @param $value, @param $model, @param $field_varname, @return string ** */

    public function setAttributes($value, $model, $field_varname) {
        return $value;
    }

    /*     * *--------------------------------------------------------------------------------------------------------------------------------------------** */
    /*     * * @param $model - profile model, @param $field - profile fields model item, @return string ** */

    public function viewAttribute($model, $field) {
        $relation = $model->relations();
        if ($this->params['relationName'] && isset($relation[$this->params['relationName']])) {
            $m = $model->__get($this->params['relationName']);
        } else {
            $m = CActiveRecord::model($this->params['modelName'])->findByPk($model->getAttribute($field->varname));
        }

        if ($m)
            return (($this->params['optionName']) ? $m->getAttribute($this->params['optionName']) : $m->id);
        else
            return $this->params['emptyField']['label'];
    }

    /*     * *--------------------------------------------------------------------------------------------------------------------------------------------** */
    /*     * * @param $model - profile model, @param $field - profile fields model item, @param $params - htmlOptions, @return string ** */

    public function editAttribute($model, $field, $htmlOptions=array()) {
        $list = array();
        if (!isset($htmlOptions['id']))
            $htmlOptions['id'] = $field->varname;
        $id = $htmlOptions['id'];
        /*         * ** */
        $relation = $model->relations();
        if ($this->params['relationName'] && isset($relation[$this->params['relationName']])) {
            $m = $model->__get($this->params['relationName']);
        } else {
            $m = CActiveRecord::model($this->params['modelName'])->findByPk($model->getAttribute($field->varname));
        }

        if ($m)
            $default_value = (($this->params['optionName']) ? $m->getAttribute($this->params['optionName']) : $m->id);
        else
            $default_value = '';
        $htmlOptions['value'] = $default_value;
        $options['source'] = 'js:function( request, response ) {
                                    $.ajax({
                                        url: "' . Yii::app()->createUrl('user/profilefield/autocomplete') . '",
                                        dataType: "json",
                                        data: {
                                            term: request.term,
                                            parentId:$("#Profile_' . $this->params['parentFieldName'] . '").val(),
                                            parentFieldName:"' . $this->params['parentFieldName'] . '",
                                            modelName:"' . $this->params['modelName'] . '"
                                        },
                                        success: function(data) {
                                            response($.map(data, function(item) {
                                                return {
                                                    label: item.label,
                                                    value: item.label,
                                                    id: item.value
                                                }
                                            }))
                                        }
                                    });
                                }';
        $options['minLength'] = $this->params['minLength'];
        $options['showAnim'] = 'fold';
        $options['select'] = "js:function(event, ui) {
            $('#" . get_class($model) . "_" . $field->varname . "').val(ui.item.id);}";
        $options = CJavaScript::encode($options);
        $basePath = Yii::getPathOfAlias('application.modules.user.views.asset');
        $baseUrl = Yii::app()->getAssetManager()->publish($basePath);
        $cs = Yii::app()->getClientScript();
        $cs->registerCssFile($baseUrl . '/css/' . $this->params['ui-theme'] . '/jquery-ui.css');
        $cs->registerScriptFile($baseUrl . '/js/jquery-ui.min.js');
        $js = "jQuery('#{$id}').autocomplete({$options});";
        $cs->registerScript('Autocomplete' . '#' . $id, $js);
        return CHtml::activeTextField($model, $field->varname, $htmlOptions) . CHtml::activehiddenField($model, $field->varname);
    }


}



and added an action to the ProfileFieldsController :

    

...
        array('allow', 
            'actions'=>array('autocomplete'),
            'users'=>array('@'),
        ),
...
    public function actionAutocomplete() {
        $results = Array();
        $model = $_GET['modelName']::model();
        $parentId = (int) $_GET['parentId'];
        $db = Yii::app()->db;
        if (!isset($model->tableSchema->columns->{$_GET['parentFieldName']})) { throw new CHttpException(500,"Invalid Request"); }
        $parentFieldName = $db->quoteColumnName($_GET['parentFieldName']);

        if (isset($_GET['term'])) {
            $search = $_GET['term'];
            $criteria = new CDbCriteria();
            $criteria->condition = "$parentFieldName = :parentId AND name like :search";
            $criteria->order = 'name';
            $criteria->params = array(':parentId'=>$parentId, ':search'=>"%$search%");
            foreach ($model->findAll($criteria) as $child) {
                $results[] = array(
                    'label' => $child->name, // value for input field
                    'value' => $child->id, // return value from autocomplete
                );
            }
            echo CJSON::encode($results);
            Yii::app()->end();
        }
    }


Only problems left are :
* the "select" option doesn't seem to work so well :
the label isn't displayed in the input, only the id is, which is why I added the "change" option, but that only works when the input loses focus.

* there's a need to add a new action to the controller. Can anyone see a way to have the widget work on it's own?

Cheers
0

#5 User is offline   Benn 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 47
  • Joined: 16-January 11
  • Location:Paris

Posted 19 February 2011 - 01:18 PM

I made the necessary corrections to the above code to solve the problem about the id being displayed instead of the label. :)
Also, the action is now safer from SQL injections.

A new issue I've found is that if the user doesn't select anything, but only types in what he wished to enter, this won't work. I'll look into it asap but if anyone has an idea, I'm all for it :)
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users