mooSelect – convert a select list into a sliding checkbox list

mooSelect
EDITED: [2009-11-12]
Well, I have taken the plunge…. I have finally my first mootools class 🙂
Despite all the tutorials claiming that it is easy, I must admit to have found it rather complicated.  I am the first to admit that I have problems with classes so this is not a reflection on mootools, rather on my limited abilities.

The final result is probably not very good as far as classes go but it works and I’m happy with it 🙂

See Demo

The background:
For a client site I needed to convert a multiple select list into a dropdown list of checkboxes.  As usual I scanned google and all the usual places where mootools scripts are posted but to no avail.  The only one that came close to what I needed was Custom Form Elements (link no longer working). Whilst this certainly looks good, for my needs it was far too complicated and I must admit (yet again) that I couldn’t even get it working as a test.  I finally gave up on my search and resolved to have a go myself.

The result is my mooSelect class.

The idea was to take a standard select multiple select list and convert it to a dropdown list of checkboxes.  This solution gains over the original as the multiple elements can be selected just by using the mouse as compared to the default method of a combination of keyboard and mouse clicks.  It also takes up less room on the page (the main reason why this alternative solution was needed by the client).

So, how does it work?

  1. The mootools code retrieves all the options from the defined select list.
  2. It creates a list of checkboxes using the same field name, values, text and even retains the “selected” value if the item has been previously selected.
  3. A “summary” box is added that serves to show the number of options selected (dynamically updating as items are removed or added) and also as the handle to toggle the checkbox list.
  4. A “close” button is also placed at the bottom of the list.
  5. The list will close itself automatically after X number of seconds (where X can be defined as an option)
  6. The new list is placed where the original select list is.
  7. The original select list element is removed.

Of course, if the user has javascript turned off, the standard multiple select list is shown as normal.

So, here is the code. Go easy with me, it is my first attempt at writing a class….

The html:

Option:<select id="my_list" multiple name="my_list" style="width:200px;">
<option value="">- select -</option>
<option value="1" >Car</option>
<option value="2" >Lorry</option>
<option value="3" >Motorbike</option>
<option value="4" >Bus</option>
<option value="5" >Train</option>
<option value="6" >Airplane</option>
</select>

The CSS:

.pseudo_select{
 background:#DDD url(images/arrows_blue.png) no-repeat right;
 width:200px;
 z-index:20;
 padding:4px;
 border:1px solid #CCC;
 }
.select_list{
 position:absolute;
 border-left:1px solid #DDD;
 border-right:1px solid #DDD;
 border-bottom:1px solid #DDD;
 width:200px;
 background:#F6FFD0;
 z-index:20;
 padding:4px;
 font-size:0.8em;
 }
.select_close{
 position:absolute;
 bottom:2px;
 right:2px;
 cursor:pointer;
 border:1px solid #CCC;
 padding:0px 4px 2px 4px;
 background:#006699;
 color:#FFFFFF;
 line-height:1.0em;
 font-size:0.8em;
 width:6px;
 text-align:center;
 }

The Javascript (mootools)

var mooSelect = new Class({
   	Implements: [Options, Events],
   	options: {
   		//start_txt:'- select options -',
   		inititalText:'- select -',	//	the initial default text (will be overwridden if the select list has it's own)
   		txt: 'options selected',	//	text for counter
   		auto_close:true,			//	to close or not to close the checklist
   		auto_close_time:5000		//	time to close the list
   	},
   	initialize: function(element,options){
   		this.setOptions(options);
   		var counter			=	0;
   		var state			=	false;
   		var select_box		=	$(element);
   		var select_options	=	select_box.getElements('option');
   		var field_name		=	select_box.getProperty('name');
   		var selected_items	=	select_box.getSelected();
   		var auto_close 		=	this.options.auto_close;
   		var auto_close_time	=	this.options.auto_close_time;
   		var initial_txt		=	this.options.inititalText;
   		
   		//create checklist from select list options
		var chk_items = '';
		var chk='';
		var initial_number='';
		
		select_options.each(function(option) {
			//	define select option value and text value
			opt_val=option.get('value');
			opt_txt=option.get('text');
			
			//	define default initial text (if it is set)
			if(opt_val=='')initial_txt		= opt_txt;
			
			//	check if item is selected
			checked='';
			if(option.get('selected')){
				checked='checked="checked"';
				counter=counter+1;	//	add 1 to counter
			}
			
			//	define number and text if
			if(counter>0) {
				initial_txt		= options.txt;
				initial_number	= counter;
			}
			//	add checkbox if value isn't empty
			if(opt_val!='')chk_items += '<label><input type="checkbox" class="sel_checkbox" name="'+field_name+'[]" '+checked+' value="'+opt_val+'">'+opt_txt+'</label><br>';
		});
		chk_items +='<div class="select_close" title="close">x</div>';
   		
   		
   		//	create new div to hold selected items counter and acts as toggle for checkbox list
		var pseudo_select=new Element('div',{
		 	'class':'pseudo_select',
		 	'html':'<span class="counter">'+initial_number+'</span> <span class="text">'+initial_txt+'</span>',
			events: {
				click: function(e) {
					//alert(auto_close_time);
					state = !state;
					if(auto_close){
						if(state) sel_list.wink(auto_close_time);
					}else{
						if(state) sel_list.reveal();
						else sel_list.dissolve();
					}
				}
			}
		}).setStyle('cursor','pointer').inject(select_box,'after');
   		
   		//create select list
		var sel_list = new Element('div',{
			'class': 'select_list',
			'html':chk_items
		}).inject(pseudo_select,'after'); 
   		
   		//	delete original select box
   		select_box.dispose();
   		
   		//	hide new select list
		sel_list.dissolve();
		
		//	close button
		sel_list.getElement('.select_close').addEvent('click',function(){
			sel_list.dissolve();
		});
		
		//	click options on select list
		var sel_checkboxes=sel_list.getElements('.sel_checkbox');
		sel_checkboxes.addEvent('click',function(){
			//	count checked checkboxes
			chk=0;
			for(var i=0;i<sel_checkboxes.length;i++){
				sel_checkboxes[i].checked? chk++:null;
			}
			if(chk==0) {
				pseudo_select.getElement('.text').set('html',''+initial_txt+'');
				pseudo_select.getElement('.counter').set('html','');
			}else{
				pseudo_select.getElement('.text').set('html',''+options.txt+'');
				pseudo_select.getElement('.counter').set('html',chk);
			}
		});
	}
 });

As always, any pointers as to how it can be improved would be greatly appreciated.

EDIT: [2009-11-12]
I have added a couple of new features to this class:

  1. On load it now uses the first option (if it has no value) as the default text for the box.
  2. Auto close can be turned off/on as an option

Post to Twitter

chris@cbolson.com

There are 8 comments in this article:

  1. 3/11/2009derschreckliche says:

    Nice class,

    one thing i would add is a lock, by setting some kind of lock-var for example, for the case the mouse is over the pseodo-select-div so it doesn’t auto-close for this case. You could reset the lock var on mouse-out…
    Just a suggestion for better usability 😉

    Thx for the script,
    Cheeeeeeeeeeeeeeeeers

  2. 3/11/2009Chris says:

    Thanks for your comments and the suggestion.
    Actually I didn’t plan on having it auto-close at all but if it didn’t it sort of “gets in the way”.
    Your idea of locking it whilst the mouse is over is a good one, I will look into seeing how to do it (any tips? 😉 ).

    I’m glad you liked it 🙂

    Chris

  3. 9/11/2009Thomas Aylott says:

    This is awesome. I’m sure I’ll actually be able to use this. Especially love the semantic / progressive enhancement fallback.

    Good stuff.

    I recommend putting this up on gist.github.com so we can fork it and update it and stuff like that.

  4. 9/11/2009Chris says:

    I’m sure I’ll actually be able to use this
    Excellent – that’s the idea 🙂
    No seriously, I am glad that you like it, especially as it is my first attempt at writing a mootools class.
    I need to address the issue that derschreckliche mentions – ie prevent the list from closing when the mouse is over the list.

    I recommend putting this up on gist.github.com so we can fork it and update it and stuff like that.
    Hold your horses, I am only just starting to get my head round classes, don’t expect too much from me 🙁 (off to take a look….)
    Thanks for your comments!

  5. 20/11/2009Elastic Multiple Select List « Chris Bolson – I digress says:

    […] on from my previous post demonstrating my mooSelect class, today I needed to create something different, again with a multiple select list. This time […]

  6. 7/11/2011Rich says:

    Great piece of code. I will definitely be able to use this…. thanks!

  7. 19/07/2012hiral says:

    hi

    i am adding all files but it shows javascript error class is not definded.

    can u please help

  8. 19/07/2012Chris says:

    Hi,
    What is your url?

    Chris

Write a comment: