unchanged
Title
Using the jamselect widget with min and max values
The problem ----------- 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](http://www.yiiframework.com/extension/jamselect/ "jamselect") widget showed up, thanks volkmar! The widget does not provide min/max filtering so I will implement a custom rule.### FirstFirst put the widget in a form ------------------------------ This is my implementation. ~~~ [php] <?php$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 ));?> ~~~#### A few things to notice 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 dataA few things to notice ---------------------- The widget isbeing pulled from a table that has only two fields, 'id' and 'word', sincelocated in `/protected/extensions not /protected/extensions/widgets`, Iwantonly point this out for people who aren't sure where toselect the word from the listput things. You have quite a bit of flexibility on where you locate widgets andstore exactly the same valuecomponents. It doesn't makes sense to me to create another folder inthe database I needextensions but perhaps on akey=>value array that looks like 'word'=>'word'.very large project it would.The $_POSTThe dropdown list datawill contain an array of selected values, this will beis 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$_POST['keywordArray'] #### Lets look atthecontroller (create)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']` Lets look at the controller (create) ------------------------------------ ~~~ [php]publicpublic function actionCreate(){ $model=new{ $model=new EventAbstract;$this->layout = '//layouts/column1';// Uncomment the following line if AJAX validation is needed // $this->performAjaxValidation($model);$this->layout = '//layouts/column1';if(isset($_POST['EventAbstract'])) { $model->attributes=$_POST['EventAbstract'];// Uncomment the following line if AJAX validation is needed // $this->performAjaxValidation($model);// I better do a check in case no keywords were selected $keywordArray = (!isset($_POST['keywordArray']) ? array() : $_POST['keywordArray']);if(isset($_POST['EventAbstract'])) { $model->attributes=$_POST['EventAbstract'];// now// Ieither have an array of keywords or an empty array // send the array tobetter do afunction to format thecheck in case no keywordsin a // comma delimited format $this->setKeywords($model,'keywords',$keywordArray);were selected $keywordArray = (!isset($_POST['keywordArray']) ? array() : $_POST['keywordArray']);// it's all done but not yet validated if($model->save()) $this->redirect(array('view','id'=>$model->id)); }// 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);$this->render('create',array( 'model'=>$model, )); }// it's all done but not yet validated if($model->save()) $this->redirect(array('view','id'=>$model->id)); } $this->render('create',array('model'=>$model)); } ~~~#### HereHere is the function that formats the keywords ---------------------------------------------- Remember the keywords are suppled by the admin so I am not doing any checking here for capitals or illegal characters.~~~ [php]publicpublic function setKeywords($model,$field,$keys){ $model->$field{ $model->$field = (empty($keys) ? null : implode(',',$keys));}} ~~~~~~ #### UpdateUpdate record ------------- And when we perform an update on the record we have to turn our comma delimited field back into an array, so similarly. ~~~ [php]publicpublic function getKeywords($delimited){ $keys{ $keys = explode(',',$delimited);returnreturn $keys;}} ~~~#### RulesRules ----- And now for the rules (in the model file)~~~ [php]publicpublic function rules(){ //{ // NOTE: you should only define rules for those attributes that//// will receive user inputs.returnreturn array(//// other rules are herearray('keywords','keywordCount','skipOnError'=>true,'maxKeys'=>6,'minKeys'=>2), //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,// //skipOnError, maxKeys and minKeys are all parameters that will besent//sent to the validation function//other rules); }); } ~~~#### TheThe validation function----------------------- ~~~ [php] public function keywordCount($attribute,$params) {$keys$keys = explode(',',$this->$attribute);//// check if there are keywords existif(!$this->$attribute) { $this->addError($attribute,'<strong>Ifif(!$this->$attribute) { $this->addError($attribute,'<strong>If you need to add a keyword please contact the administrator</strong>');} //} // check if there are enough keywordsif(count($keys)if(count($keys) < $params['minKeys']){ $this->addError($attribute,'Please{ $this->addError($attribute,'Please choose at least '.$params['minKeys'].($params['minKeys'] > 1 ? ' keywords' :' keyword'));} //} // check if there are too many keywordsif(count($keys)if(count($keys) > $params['maxKeys']){ $this->addError($attribute,'You{ $this->addError($attribute,'You have chosen too many keywords max = '.$params['maxKeys']);} }} } ~~~Now the user can select between 2 and 6 keywords. doodle