Yii 1.1: Using the jamselect widget with min and max values

2 followers

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 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   
$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 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)

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.

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.

public function getKeywords($delimited)
{
    $keys = explode(',',$delimited);
    return $keys;
}

Rules

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
    );
}

The validation function

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 to leave your comment.

Write new article