[...]
-----------
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.
### First put the widget in a form
------------------------------
This is my implementation.
```php
<?php
$this->widget(
'application.extensions.asmselect.JAMSelect',
array([...]
'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 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']
`
#### Lets look at the controller (create)
------------------------------------
```php
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
,
));
}
```
####
Here 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
public function setKeywords($model,$field,$keys)
{
$model->$field = (empty($keys) ? null : implode(',',$keys));
}
```
####
Update 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
public function getKeywords($delimited)
{
$keys = explode(',',$delimited);
return $keys;
}
```
#### Rules
-----
And now for the rules (in the model file)
```php
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
);
);
}
```
#### The validation function
-----------------------
```php
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