I needed to have users select from a list of keywords, in this example they must select at least two keywords but they cannot select more than six.
The keywords will be stored in a text field in a comma delimited format. The keywords will be created by the site administrator.
In a very timely fashion the jamselect widget showed up, thanks volkmar!
The widget does not provide min/max filtering so I will implement a custom rule.
This is my implementation.
$this->widget( 'application.extensions.asmselect.JAMSelect', array( 'selected'=>$this->getKeywords($model->keywords), 'data'=>CHtml::listData(Keywords::model()->findAll(),'word', 'word'), 'htmlOptions'=>array( 'title'=>'Select up to six keywords', 'name'=>'keywordArray' ), 'animate'=>true ));
The widget is located in /protected/extensions not /protected/extensions/widgets, I only point this out for people who aren't sure where to put things. You have quite a bit of flexibility on where you locate widgets and components. It doesn't makes sense to me to create another folder in extensions but perhaps on a very large project it would.
The dropdown list data is being pulled from a table that has only two fields, id and word, since I want to select the word from the list and store exactly the same value in the database I need a key=>value array that looks like word'=>'word.
The $_POST data will contain an array of selected values, this will be in $_POST['keywordArray']
public function actionCreate() { $model=new EventAbstract; $this->layout = '//layouts/column1'; // Uncomment the following line if AJAX validation is needed // $this->performAjaxValidation($model); if(isset($_POST['EventAbstract'])) { $model->attributes=$_POST['EventAbstract']; // I better do a check in case no keywords were selected $keywordArray = (!isset($_POST['keywordArray']) ? array() : $_POST['keywordArray']); // now I either have an array of keywords or an empty array // send the array to a function to format the keywords in a // comma delimited format $this->setKeywords($model,'keywords',$keywordArray); // it's all done but not yet validated if($model->save()) $this->redirect(array('view','id'=>$model->id)); } $this->render('create',array('model'=>$model)); }
Remember the keywords are suppled by the admin so I am not doing any checking here for capitals or illegal characters.
public function setKeywords($model,$field,$keys) { $model->$field = (empty($keys) ? null : implode(',',$keys)); }
And when we perform an update on the record we have to turn our comma delimited field back into an array, so similarly.
public function getKeywords($delimited) { $keys = explode(',',$delimited); return $keys; }
And now for the rules (in the model file)
public function rules() { // NOTE: you should only define rules for those attributes that // will receive user inputs. return array( // other rules are here array('keywords', 'keywordCount', 'skipOnError'=>true, 'maxKeys'=>6, 'minKeys'=>2), // keywords is the field in the table currently holding the submitted value // $model->keywords // keywordCount is the function (in the model) that will do the validation // //skipOnError, maxKeys and minKeys are all parameters that will be //sent to the validation function other rules ); }
public function keywordCount($attribute,$params) { $keys = explode(',',$this->$attribute); // check if there are keywords exist if(!$this->$attribute) { $this->addError($attribute,'<strong>If you need to add a keyword please contact the administrator</strong>'); } // check if there are enough keywords if(count($keys) < $params['minKeys']) { $this->addError($attribute,'Please choose at least '.$params['minKeys'].($params['minKeys'] > 1 ? ' keywords' :' keyword')); } // check if there are too many keywords if(count($keys) > $params['maxKeys']) { $this->addError($attribute,'You have chosen too many keywords max = '.$params['maxKeys']); } }
Now the user can select between 2 and 6 keywords.
doodle
Be the first person to leave a comment
Please login to leave your comment.