Using CJuiAutoComplete as a list selector with form builder

Hi

I’m working on a extension to the CJuiAutoComplete widget. This extension is aimed as an smart list selector to use in traditional forms or forms built with the new form builder technology.

Let’s say we have the following scenario:

I like to describe relations between companies. For this I have create a table named company with the following fields:

* id (unique id of the company)


* name (name of company)


* owner (id of the company owning this company)

The interesting parts of the controller (Company.php) looks like this:


class Company extends CActiveRecord

{

        ...


        public function rules()

        {

                return array(

                        array('name','length','max'=>45),

                        array('owner','exist',

                            'className'=>'Company',

                            'attributeName'=>'id',

                            'skipOnError'=>true),

                            );

        }


        public function relations()

        {

                return array(

                        'OwnedBy'=>array(self::BELONGS_TO,'Company','owner'),

                );

        }


        ...

}

In the update form for this table i don’t want the user to enter the id of the owner company. Instead I would like to give the user the opportunity select the owner company by name. However, this will be inconvenient when the list of companies is getting large. Therefore I thought of using the CJuiAutoComplete widget in combination with an ajax request to give a reduced list of companies which names matching a text input from user. I would also like to use the form builder to create a form. To be able to sort all this out I ended up constructing my own widget based on the CJuiAutoComplete.

The widget is used with the form builder in the following way:


return array(

        'title' => 'Update company',

        'elements' => array(

                'name' => array(

                        'type' => 'text',

                        'maxlength' => 45,

                        'width' => 200,

                ),

                'owner' => array(

                        'type'=>'application.extensions.CJuiAutoCompleteWithId',

                        'source'=>Yii::app()->createUrl('company/autocomplete'),

                ),

        'buttons' => array(

                'update' => array(

                        'type' => 'submit',

                        'label' => 'Update',

                ),

        ),

);

And the corresponding code, to serve the autocomplete request, would be put in the controller:




public function actionAutocomplete() {

    $results = Array();

        if (isset($_GET['term'])) {

            $search=$_GET['term'];

            foreach (Company::model()->findAll("name like '%$search%'") as $company) {

                $results[] = array( 'label'=>$company->real_name, // label for dropdown list

                                    'value'=>$company->name, // value for input field

                                    'id'=>$company->id, // return value from autocomplete

                                  );

        }

        echo CJSON::encode($results);

        Yii::app()->end();

    }

The code for the new widget:


Yii::import('zii.widgets.jui.CJuiAutoComplete');


class CJuiAutoCompleteWithId extends CJuiAutoComplete {


    public function run() {

        list($name, $id) = $this->resolveNameID();


        if (isset($this->htmlOptions['id']))

            $id = $this->htmlOptions['id'];

        else

            $this->htmlOptions['id'] = $id;


        if (isset($this->htmlOptions['name']))

            $name = $this->htmlOptions['name'];

        else

            $this->htmlOptions['name'] = $name;


        //Display a textfield that has no data connection

        $textfieldId = $id . "_text";

        $htmlOptions = $this->htmlOptions;

        $htmlOptions['id'] = $textfieldId;

        //TODO: The text field has to be filled with text if the field has a value

        echo CHtml::textField($textfieldId, "", $htmlOptions);

        echo CHtml::ajaxButton('Clear','',array(

                'success' => "js:function(){\$('#$id').val(0);\$('#$textfieldId').val('');}",

            ));


        //Display the hidden field that has the actual data connection

        if ($this->hasModel())

            echo CHtml::activeHiddenField($this->model, $this->attribute, array('id' => $this->htmlOptions['id']));

        else

            echo CHtml::hiddenField($name, $this->value, array('id' => $this->htmlOptions['id']));


        if ($this->sourceUrl !== null)

            $this->options['source'] = CHtml::normalizeUrl($this->sourceUrl);

        else

            $this->options['source'] = $this->source;


        $this->options['select'] = "js:function(event,ui){\$(\"#$id\").val(ui.item.id);}";

        $options = CJavaScript::encode($this->options);

        $js = "jQuery('#{$textfieldId}').autocomplete($options);";


        $cs = Yii::app()->getClientScript();

        $cs->registerScript(__CLASS__ . '#' . $id, $js);

    }


}



Problem:

This all works fine with one small exception: When i bring up the update form the text field representing the owning company would be empty. I would like this field to start with the name of the company corresponding to the id in the owner field. But i haven’t been able to solve that. I have tried the following construction:


echo CHtml::textField($textfieldId, $this->model->OwnedBy->name, $htmlOptions);

The questions:

Does this look like a reasonable way to fulfil my requirements or are there better ways?

If this is a good solution, how to I solve the above mentioned problem?

Any comments or suggestions would be much appreciated.

P.S. I’m sorry for the large post, but I didn’t find any shorter way of describing the situation. Hopefully the code can help somebody in some way though.

The post has been updated. Somwere along the road big pices of the post was lost an only a part of the message was displayed here at the forum. The content is now updated with the full post.

There is no need to post the same question in two different sections…

I deleted your post in the "tips…" section…

Since i got no reaction on my previos post I will try to narrow down the subject:

I tired put in this code in the widget:


Yii::import('zii.widgets.jui.CJuiAutoComplete');


class CJuiAutoCompleteWithId extends CJuiAutoComplete {


    public function run() {

        /*... code removed ...*/


        if ($this->hasModel())

           $name=$this->model->OwnedBy->name;

        else

           $name='';


        /*... code removed ... */

    }


}



But this construction does not work. The OwnedBy is a relation in the AR-model.

But the construction $this->model->OwnedBy returns a reference to a CJuiAutoCompleteWithId object!?

What am I doing wrong here?