Using the jamselect widget with min and max values

You are viewing revision #2 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.

« previous (#1)next (#4) »

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