Discussion and Questions on EJuiAutoCompleteFkField

Please post any discussion or questions related to extension EJuiAutoCompleteFkField in this topic.

I can not find the error in my example. I need help.

My tables:




CREATE TABLE school (

  idschool INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,

  name VARCHAR(40) NOT NULL,

  PRIMARY KEY(idschool)

);




CREATE TABLE student (

  idstudent INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,

  idschool INTEGER UNSIGNED NOT NULL,

  name VARCHAR(40) NOT NULL,

  PRIMARY KEY(idstudent),

  FOREIGN KEY(idschool) REFERENCES school(idschool)

);



Relation:

A school has many students

A student belongs to a school

Steps

1)unzip extension - checked

2)make sure config/main.php has - checked




import=>array(

          'application.extensions.*',

          ...

      ),



3)ensure the relationship exists in the model - checked

student.php (Model) - checked




        public function relations()

	{

		return array(

			'schoolx' => array(self::BELONGS_TO, 'School', 'idschool'),

		);

	}



  1. optionally - I’ll use the normal attribute (name)

5)in the _form.php (student)




       echo $form->labelEx($model, 'idschool');

		$this->widget('EJuiAutoCompleteFkField', array(

		  'model'=>$model, 

		  'attribute'=>'idschool',	  

		  'sourceUrl'=>'findSchool', 		  

		  'showFKField'=>true,

		  'FKFieldSize'=>15, 

		  'relName'=>'schoolx', 

		  'displayAttr'=>'name',  

		  'autoCompleteLength'=>40,

		));


       echo $form->error($model,'idschool');



6)in controller the method to return the autoComplete data. (StudentController.php)


	

public function actionFindSchool() {

       $q = $_GET['term'];

       if (isset($q)) {

           $criteria = new CDbCriteria;

           

           $criteria->condition = 'name like :q';

           $criteria->order = 'name asc'; 

           $criteria->limit = 10; 

           

           $criteria->params = array(':q' => trim($q) . '%'); 

           $schools = school::model()->findAll($criteria);

 

           if (!empty($schools)) {

               $out = array();

               foreach ($schools as $p) {

                   $out[] = array(

                       

                       'label' => $p->name,  

                       'value' => $p->name,

                       'id' => $p->idschool, 

                   );

               }

               echo CJSON::encode($out);

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

           }

       }

}



  1. in the Controller loadModel() method. (StudentController.php)

 

        public function loadModel()

	{

		if($this->_model===null)

		{

			if(isset($_GET['id']))

				$this->_model=student::model()->with('schoolx')->findbyPk($_GET['id']);

			if($this->_model===null)

				throw new CHttpException(404,'The requested page does not exist.');

		}

		return $this->_model;

	}



what problem or error are you getting ?

The text field is not receiving data for autocompletion.

The problem is also not obvious to me from looking at your code.

to debug this problem you should use several tools:

  1. in Firefox browser, install Firebug. Enable firebug. When you type in the auto-Complete field, watch the POST data and the response. See if an error is generated

  2. you need a programming editor with debugger installed. I use NetBeans 6.9.1 and Xdebug. Installing and configuring Xdebug for apache is beyond the scope of help I can offer; but there are plenty of tips in the forum and you can google it.

after xdebug is installed and working properly then you should set a breakpoint in the actionFindSchool() method and step-through to see if any data is selected and returned.

Another option is to trace the SQL commands generated in yii. in config/main, for the ‘log’ component, change ‘levels’=>‘error,warning,trace’,

add ‘categories’=>‘system.db.*’,

then tail the application.log and see if the SQL being generated makes sense. If it does, paste the generated SQL into whatever db front-end tool you use and see what results you get.

I found the problem with Firebug.

The requested URL was with the status: 404 Not Found.

Observe an example of a call: http://localhost/foreignkey/findSchool?term=anh

Solution:

In the _form.php (student)




                echo $form->labelEx($model, 'idschool');

		$this->widget('EJuiAutoCompleteFkField', array(

		  'model'=>$model, 

		  'attribute'=>'idschool',	  

		'sourceUrl'=>'index.php?r=student/findSchool', 		  

		  'showFKField'=>true,

		  'FKFieldSize'=>15, 

		  'relName'=>'schoolx', 

		  'displayAttr'=>'name',  

		  'autoCompleteLength'=>40,

		));



Thanks Jeremy! His answer was very helpful.

Excuse my english, I am a brazilian with bad english. The post was based on the translator.

Thanks Jeremy for the very practical widget, hope they incorporate it into CORE …

Q. By the way, what is the expected behavior of the widget on UPDATE ?

I mean it works great for CREATE, but on Update although it shows the correct data, when it is changed the autocomplete is not triggered :( making impossible to change the originally selected value.

Is there something else that I have missed that is needed to allow same functionality on UPDATE to work ?

thanks much !

This is a very good point. Right now, one can delete the current value from the field (using icon to the right of the field); then enter a new value. But the user must understand how to do it. There is no way to over-type the currently-displayed value, and have the autocompleter work again. I will consider this for a future enhancement. You can star the extension to be notified when any new versions or comments are posted.

  • Jeremy

Thanks for the quick response.

I did notice the [x] to remove the value, but when typing again the term request is not being triggered at all :( [on UPDATE] !

These are the settings I’m using, that work on CREATE




<?php echo $form->hiddenField($model,'ubicacion', array('readonly'=>'readonly')); ?>

<?php $this->widget('EJuiAutoCompleteFkField',array( 

      	 		'model'=>$model,

  	 		'attribute'=>'ubicacion', //the FK field (from CJuiInputWidget)

 	 		// controller method to return the autoComplete data (from CJuiAutoComplete)

 	 		'sourceUrl'=>'buscaUbicacion',

  	 		// defaults to false.  set 'true' to display the FK field with 'readonly' attribute.

 	 		'showFKField'=>false,

 	 		 // display size of the FK field.  only matters if not hidden.  defaults to 10

 	 		'FKFieldSize'=>11,

  	 		'relName'=>'LocatedIn', // the relation name defined above

 	 		'displayAttr'=>'descripcionYUbicacion',  // attribute or pseudo-attribute to display 

	 		// length of the AutoComplete/display field, defaults to 50

 	 		'autoCompleteLength'=>50,

 	 		// any attributes of CJuiAutoComplete and jQuery JUI AutoComplete widget may

  	 		// also be defined.  read the code and docs for all options

 	 		'options'=>array(

 	 		 	// number of characters that must be typed before

  	 		 	// autoCompleter returns a value, defaults to 2

 	 		 	'minLength'=>3,

  	 		),

 		 )); ?>



Silly me the request is being triggered but is pointing to the wrong URL … thanks ;)

I’m glad it is working for you.

[edit]

I tried again - actually the extension does work properly when over-typing. Please try again now that you have the controller method set correctly, and see if it works.

[/edit]

One other question: why are you putting a hidden field of the model attribute, before the autocompleter? It renders such a hidden field on its own…

Jeremy,

Sorry I didn’t update, in fact I removed the hidden field in the final working solution. But the working solution has IMHO two important elements:

  • sourceUrl should not use ‘controller/action’ notation alone since in update the rendered URL is corrupted

  • validation rule for the attribute should NOT use: array(‘attribute’,‘exist’) for some reason that I don’t understand such validation fails on UPDATE even though the value exist. It shows a message: <attribute> “<value>” is invalid. Not sure if it’s a bug in the CExistValidator implementation or the EJuiAutoCompleteFkField or I misunderstood the ‘exist’ validation concept.

[html]

&lt;div class=&quot;row&quot;&gt;


	&lt;?php echo &#036;form-&gt;labelEx(&#036;model,'ubicacion'); ?&gt;


	&lt;?php &#036;this-&gt;widget('EJuiAutoCompleteFkField',array(


   	 		'model'=&gt;&#036;model,


 		'attribute'=&gt;'ubicacion', //the FK field (from CJuiInputWidget)


 		// controller method to return the autoComplete data (from CJuiAutoComplete)


 		'sourceUrl'=&gt;Yii::app()-&gt;createUrl(&quot;/banco/buscaUbicacion&quot;),


 		// defaults to false.  set 'true' to display the FK field with 'readonly' attribute.


 		'showFKField'=&gt;false,


 		 // display size of the FK field.  only matters if not hidden.  defaults to 10


 		'FKFieldSize'=&gt;11,


 		'relName'=&gt;'LocatedIn', // the relation name defined above


 		'displayAttr'=&gt;'descripcionYUbicacion',  // attribute or pseudo-attribute to display


 		// length of the AutoComplete/display field, defaults to 50


 		'autoCompleteLength'=&gt;50,


 		// any attributes of CJuiAutoComplete and jQuery JUI AutoComplete widget may


 		// also be defined.  read the code and docs for all options


 		'options'=&gt;array(


 		 	// number of characters that must be typed before


 		 	// autoCompleter returns a value, defaults to 2


 		 	'minLength'=&gt;3,


 		),


	 )); ?&gt;


	&lt;?php echo &#036;form-&gt;error(&#036;model,'ubicacion'); ?&gt;


&lt;/div&gt;

[/html]

thanks again Jeremy for this extension, it is really useful.

@1661design: Thanks for the feedback.

I updated the documentation in the extension to use createUrl().

I’ve never used the “exist” validator. Did you follow the example given in CExistValidator documentation, at the bottom? You need something like this:




array('FkFieldName','exist','allowEmpty'=>true, 'attributeName'=>'fieldName','class'=>'FkTableName'),



Hi Jeremy,

Thank you for the excellent extension.

I got a problem though, in my case, sometimes I add the option ‘*’ for all values. Especially, during development time, I used mock data, I could not remember what would be the name, so I need some kind of magic term to display all options. How could I do this?

I tried this but not working as expected




    /**

     *  Data provider for EJuiAutoCompleteFkField for categoryFk field

     */

    public function actionFindCategory() {

        $q = $_GET['term'];

        if ($q == '**') {

            $q = '*';

        }


        if (isset($q)) {

            $criteria = new CDbCriteria;

            //condition to find your data, using q as the parameter field

            $criteria->condition = 'name like :txt OR code like :txt';

            $criteria->order = 'name ASC'; // correct order-by field

            $criteria->limit = 10; // probably a good idea to limit the results

            // with trailing wildcard only; probably a good idea for large volumes of data

            $criteria->params = array(':txt' => '%' . trim($q) . '%');


            $categories = Category::model()->findAll($criteria);


            if (!empty($categories)) {

                $out = array();

                foreach ($categories as $cat) {

                    $out[] = array(

                        // expression to give the string for the autoComplete drop-down

                        'label' => $cat->name,

                        'value' => $cat->name,

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

                    );

                }


                echo CJSON::encode($out);


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

            }

        }

    }



The default value for options->minLength is 2. If you haven’t changed this, then you can simply type %% in the auto-complete field. Two characters are enough the trigger the auto-completer; and using % (SQL Wildcard character) will return all records. No coding changes are needed. If you’ve set minLength to something other than 2, then simply type that number of % characters.

If you want to use the * character, you still have minLength to contend with. Personally I don’t see how typing ** is any easier than %%, but if you want, change the code to substitute % for *. You might want to bracket this logic with IF (defined(‘YII_DEBUG’)) so it only works in a dev environment.

  • Jeremy

Hi, i don’t unterstand the attribute “term” in this


$_GET['term']

.

someone can explain it to me plz.

thx

EJuiAutoCompleteFkField extends the base class CJuiAutoComplete, which makes an AJAX call after [minLength] characters have been typed, and the user stops typing for the default duration. The AJAX call has the search string in a GET parameter "term".

Hi Jeremy,

Did not think of "%%" before…

Now, new problem, I had a multiple modules, here is my view




...

<table id="details" style="width: auto; margin-left: 15px; float: left;">

            <thead>

                <tr>

                    <th style="width: 100px; text-align: center;">Gudang</th>

                    <th style="width: 250px; text-align: center;">Produk</th>

                    <th style="width: 100px; text-align: center;">Kode bets</th>

                    <th style="width: 100px; text-align: center;">Jumlah</th>

                    <th style="width: auto"><?php echo CHtml::link(CHtml::image(Yii::app()->request->baseUrl . '/images/add_ico.png'), '', array('onClick' => 'addDetail($(this))', 'class' => 'add')); ?></th>

                </tr>

            </thead>

            <tbody>

                <?php foreach ($details as $id => $detail): ?> 

                    <?php $this->renderPartial('_formDetail', array('id' => $id, 'model' => $detail, 'form' => $form), false, true); ?>

                <?php endforeach; ?>

            </tbody>

        </table>

...



here is in _formDetail




<tr>    

    <td> 

        <?php echo $form->textField($model, "[$id]warehouseFk", array('style' => 'width: 100px;')); ?>

        

    </td>

    <td>

        <?php echo $form->textField($model, "[$id]productFk", array('style' => 'width: 250px;')); ?> 

    </td>

    <td> 

        <?php echo $form->textField($model, "[$id]batchNo", array('style' => 'width: 100px; text-align: center;')); ?>

    </td>

    <td> 

        <?php echo $form->textField($model, "[$id]quantity", array('style' => 'width: 100px; text-align: right;')); ?>

    </td>

    <td>

        <?php echo CHtml::link(CHtml::image(Yii::app()->request->baseUrl . '/images/remove_ico.png'), '', array('class' => 'delete', 'onClick' => 'deleteDetail($(this))')); ?>

    </td>

</tr>



I want to substitute the textfield for warehouse with




        <?php

        $this->widget('EJuiAutoCompleteFkField', array(

            'model' => $model,

            'attribute' => '[$id]warehouseFk', //the FK field (from CJuiInputWidget)

            // controller method to return the autoComplete data (from CJuiAutoComplete)

            'sourceUrl' => Yii::app()->createUrl('/transaction/findWarehouse'),

            // defaults to false.  set 'true' to display the FK field with 'readonly' attribute.

//            'showFKField' => true,

            // display size of the FK field.  only matters if not hidden.  defaults to 10

//            'FKFieldSize' => 15,

            'relName' => 'warehouse', // the relation name defined above

            'displayAttr' => 'warehouseName', // attribute or pseudo-attribute to display

            // length of the AutoComplete/display field, defaults to 50

//            'autoCompleteLength' => 60,

            // any attributes of CJuiAutoComplete and jQuery JUI AutoComplete widget may 

            // also be defined.  read the code and docs for all options

            'options' => array(

                // number of characters that must be typed before 

                // autoCompleter returns a value, defaults to 2

//                'minLength' => 3,

            ),

        ));

        ?>



but the autocomplete is never called, any hints?

Cheers,

Daniel

use firebug to see what is happening. Make sure the ajax GET is happening after you type at least 2 characters in the autoComplete field. Examine the response from the server - maybe there’s an error.