EchMultiSelect Widget

When you use the relation name as the dropDownAttribute, that is not enough to make the dropDownList know which elements should be preselected. That’s because dropDownList needs an array of elements/values, not an array of objects.

If ‘categories’ is a relation in the model Post for example, then:




$model = Post::model()->findByPk($id);

$pcs = $model->categories; // This is an array of objects. Not a array of values.



returns an array of objects, which cannot be utilized by dropDownList.

You need to do something like this:




$model = Post::model()->findByPk($id);

$postCategories = PostCategories::model()->findAll(array('select'=>'category_id','condition'=>'post_id='.$id);

$categories = array();

foreach($postCategories as $pcs) {

   $categories[] = $pcs->category_id;

}

$model->categories = $categories;



After that, ‘$model->categories’ is an array of ids/values, that dropDownList can utilize, and the values will be preselected.

Note that after clicking ‘update’ in the form, the newly selected values will not be automatically saved in the relation table PostCategories. You have to take care of it in your actionUpdate() method of your Post model.

I recommend this article: Handling Related Models in Yii Forms from Larry Ullman.

This worked perfectly, thanks so much!

This was actually my next question - what if I want to do it simpler (without relations)? I currently have in my model:




        public static $TypeArray

          = array(

                 1=>'TYPE1',

                 2=>'TYPE2',

                 3=>'TYPE3',

                 4=>'TYPE4',              

                 5=>'TYPE5',);



and my view file has




                $types = Model::$TypeArray;                                 

                $this->widget('ext.widgets.EchMultiselect', array(

                'model'=>$TypeModel,

                'dropDownAttribute'=>'type',  //I did as you said and created new array $type in controller    

                'data'=>$types, 



And my table has field_1, field_2, field_3, field_4, field_5, each which gets set to 0 or 1 depending on whether they get checked (working thanks to your code suggestion!).

So how do I get it to now show the already checked values after POST? Thanks so much.

Hi jcny, glad it worked so far…

Now, in the actionUpdate() method of your controller, you could do something like this:




$TypeModel = TypeModel::model()->findByPk($id);

for($i=1;$i<=N;$i++) {

    if($TypeModel->field_$i == 1) $TypeModel->type[$i] = 1;

    else $TypeModel->type[$i] = 0;

}



This way, you fill the new variable/array type of your model according to the values in your table, before your render the form.

Since the widget in your view file has type as its dropDownAttribute, and type is an array with values, the widget will/can use these values to preselect the options.

Best regards…

This makes sense - I am running into an error though with $TypeModel->field_$i - my editor is saying that doesn’t work (the field_$i). I tried it with field_.$i but that doesn’t work either. Any thoughts?

sorry, I was fast-typing some kind of pseudocode.

The following works (this time I tested):




// To get the value of the model-attribute

$fieldname = 'field_'.$i;

$type[$i] = $TypeModel->attributes[$fieldname];


// And if you want to set the value of the model-attribute at some point:

$TypeModel->setAttribute($fieldname, $tpye[$i]);



Great, this worked perfect. I ended up using something like this:




for($i=1;$i<=5; $i++) {

$fieldName = 'field_'.$i;    

if ($TypeModel->$fieldName == 1) //check model for 1 or 0                           

 $TypeModel->type[$i] = $i;  //using $i instead of 1 since we need checkbox value, but model only stores 0 or 1 

    else $TypeModel->type[$i] = 0;



Again, really appreciate your help and instruction!

I’m glad if I could help.

When I think about it, the ‘0’ values are probably not needed.

So the following should also work:




if ($TypeModel->$fieldName == 1) $TypeModel->type[] = $i;  //just add the index that should be checked into the array $type

// else do nothing.



Doesn’t make much difference if there are not so many fields. But for optimization freaks like me, it’s the principle that counts :)

Hi,

A great extension!

I tested it but I can’t get the options take the whole width of the widget. They are left-aligned (about on the 100 first px I think) even if I increase the width of the widget.

Do you have a solution for me?

Many Thanks

Hi Denis,

I use the extension like the following, and the width of the options-box is the same as the widget (drop-down-button) itself:




$this->widget('ext.widgets.EchMultiselect', array(

	'model'=>$model,

	'data' => $idata,

	'dropDownAttribute' => 'itypes',

	'dropDownHtmlOptions'=> array(

		//'class'=>'span-10',

		'style'=>'width:450px',

	),

	'options' => array( 

		'selectedList'=>5,

		'multiselect'=>true,

		'header'=>true,

		'filter'=>true,

	),

)); ?>



It works both when I specify the ‘style’ in the ‘dropDownHtmlOptions’, or the ‘class’.

Can you try this code and see if it works for you?

If not, can you post your code; or the URL of the site, if it is online?

Best regards…

Hi c@cba,

I tried your code but it does not work.

Here is an example of the result and my code :


$this->widget('ext.widgets.EchMultiselect', array(

	        'name'=>'test',

	        'data' => array('Test1','Test2'),

	        

	        'dropDownHtmlOptions'=> array(

	'class'=>'span-10',

	                //'style'=>'width:450px',

	),

	        'options' => array( 

	                'selectedList'=>5,

	                'multiselect'=>true,

	                'header'=>true,

	                'filter'=>true,

	),

	));

Here is the file 2898

test_echmultiselect.png

I assume that the same problem exists when you define the width via ‘width:450px’ instead of span-10?

It seems to me, that there are other style-declarations (like width, or float:right etc.) that affect the checkboxes and make them appear that way…

Do you use Firebug (the add-on for firefox)?

With firebug you could determine what styles exactly are applied to the checkboxes.

Sometime css-styles do behave unexpectedly and if there are more than one css-file, something overrides the other and there is no way to know what happpens without some tool like firebug…

Best regards…

I’ve juste tested this and it appears that the ‘ui-corner-all’ style is applied to the label tag. Is that correct?

Yes, the labels have the class ‘ci-corner-all’, that only has the effect of rounding the corners of the label (the gray area).

the <ul> element has the class ‘ui-multiselect-checkboxes’, so it looks like this:




<ul class="ui-multiselect-checkboxes">

  <li>

    <label class="ui-corner-all"> ... </label>

  </li>

</ul>



It is really difficult to say something without seeing the code, but I have the suspicion that somewhere in your css files there is a style declaration for the ‘label’ element that sets a fixed width for it and makes the text within right aligend, i.e. something like this:




label {

   width:100px;

   text-align:right;

}



This is often done to style form elements, where a label is followed by a text-field for example, to produce forms like here: http://jeffhowden.com/code/css/forms/

Note that the labels are right aligned and how they are styled further below:




form div label {

  display: block;

  float: left;

  width: 130px;

  padding: 3px 5px;

  margin: 0 0 5px 0;

  text-align: right;

}



More than likely something like this is happening in your case…

Best regards…

I found the problem.

I think there is a conflict with the Bootstrap extension (it overwrite indeed the label tag).

I’m not an expert in css, do you have a workaround for me?

Many thanks

In the assets folder of the extension, there is the file "jquery.multiselect.css"

Add the following code into that file should work:




.ui-multiselect-checkboxes label  { width:auto !important; text-align:left !important; }



Best regards…

Ok, works like a charm. I change the width:auto (the cornered box width takes just the label characters length) to 98% (the scroll bar hides the end)

Hi,

I want to tune the component to fit my needs.

I want to display it like a multiple checkbox list but without the user to click on the scroller => always display the entire list (and abusing : is it possible in that case that the checkboxes take the entire height before the next component? - css? my weakness)

Is it possible?

So you don’t want a “drop-down-checkbox-list”?

You want a list of checkboxes that are always visible?

EchMultiSelect is a JQuery widget, there is a lot of javascript-code behind its behavior ((dis)appearing of the boxes etc.).

It will not be easy to make it behave like you want it to, it is not just a matter of css.

So if you don’t need/want a drop-down element, I would recommend for example the CheckBoxList of Yii:

http://www.yiiframework.com/doc/api/1.1/CActiveForm#checkBoxList-detail

Best regards…