Tabs & Lists With Selectability
I’ve recently come up with a need to allow users to view a list of options from which to choose. Do to screen restraints and readability, I opted to use the tabbing functionality I wrote about previously. In the process, however, I wrote some javascript that allows me to add the ‘pick and choose’ functionality to any pair of lists, or single list, I choose.
Single List Mode: This is real simple. The user has a list of items to select from. When the select the item, the ‘selected’ class is added to that item. When they de-select the item, the ‘selected’ class is removed. This is tracked with a hidden input element with the id ‘ls_update_list_array’.
Dual List Mode: When the user views ‘Categories Selected’ (in this case, shown by default), they will see a list of categories currently selected. Under ‘All Available Categories’, they get a complete list of categories to selected from (in this case, minus those categories already selected). We want the user to be able to either add to the list of ‘Currently Selected’ by clicking on the ‘All Categories’ list, or remove items by clicking on them under ‘Currently Selected’. When they click on an item in either list, it is moved from list to the other. This is tracked with a hidden input element with the id ‘ls_update_list_array’.
ls_update_list_array: This is provided simply to allow for an easy form post action. Rather than having Javascript determine when the form is posted and then grabbing the list as an array and blah, blah, blah, you get the list automatically on post.
The HTML
<div id="tabs"><b class="active"><a href="#selected-categories">Currently Selected Categories</a></b><b class="inactive"><a href="#all-categories">All Available Categories</a></b></div> <ul id="selected-categories" class="tab"> <li id="item1" class="li-item selected">Item 1 text</li> <li id="item3" class="li-item selected">Item 3 text</li> <li id="item7" class="li-item selected">Item 7 text</li> <li id="item8" class="li-item selected">Item 8 text</li> </ul> <ul id="all-categories" class="tab"> <li id="item1" class="li-item">Item 1 text</li> <li id="item2" class="li-item">Item 2 text</li> <li id="item3" class="li-item">Item 3 text</li> <li id="item4" class="li-item">Item 4 text</li> <li id="item5" class="li-item">Item 5 text</li> <li id="item6" class="li-item">Item 6 text</li> <li id="item7" class="li-item">Item 7 text</li> <li id="item8" class="li-item">Item 8 text</li> </ul>
The CSS
You do not need to use this. You can use your own CSS.
#tabs { margin: 0 0 -2px 0; height: 45px; }
#tabs b { display: block; float: left; margin: 0px; background: #fff; font-weight: normal; }
#tabs b.active { background: #e0d3e3; }
#tabs b.active a { color: #663366; }
#tabs b.inactive a:hover { background: #f5edf6; }
#tabs b a { display: block; color: #a989b0; padding: 10px; border: 1px solid #d3d3d3; text-decoration: none; }
#tabs b a:hover { background: #f5edf6; }
.tab { clear: both; width: 100%; height: 250px; margin: 0; padding: 0!important; overflow: hidden; overflow-y: scroll; background: #fff; border: 1px solid #d3d3d3; }
.tab li { font-weight: normal; padding: 10px!important; margin: 0!important; border-bottom: 1px dotted #d3d3d3; cursor: pointer; color: #663366; background-image: none!important; }
.tab li:hover { background: #e0d3e3; }
.tab li.selected { background: #956a99; color: #fff; }
.tab li.selected:hover { background: #b592b8; color: #fff; }
The Javascript
bind events to the lists
Dual Lists Mode:
if ( $('#selected-categories').length > 0 ) {
ls.init({
variable : '#selected-categories', // the list that is updated to reflect user's selections
clickable : 'li', // the element on which to bind the click event
update_list : true,
constant : '#all-categories' // the list the user makes selections from
});
}
Single List Mode:
if ( $('#selected-categories').length > 0 ) {
ls.init({
variable : '#selected-categories', // the list that is updated to reflect user's selections
clickable : 'li', // the element on which to bind the click event
update_list : false
});
}
the code that makes it work
ls = {
/* *************************************************************************
*
* start the initial binding of the list columns
*
************************************************************************* */
init : function( params ) {
var p = params;
$(p._variable + " " + p._clickable).unbind('click');
$(p._variable + " " + p._clickable).bind('click', function() {
ls.move_left( p, $(this) );
});
if ( p._update_list ) {
$(p._constant + " " + p._clickable).unbind('click');
$(p._constant + " " + p._clickable).bind('click', function() {
ls.move_right( p, $(this) );
});
}
// update the list array field
ls.track_selected_elements( p );
},
/* *************************************************************************
* END :::
************************************************************************* */
/* *************************************************************************
*
* Moves selected element from the variable list to the constant list
*
************************************************************************* */
move_left : function( p, obj ) {
var p = p;
if ( p._update_list ) {
obj_id = $( obj ).attr('id');
// this object exists in the other list
// just remove it from existing list
if ( $( p._constant ).find( '#' + obj_id ).length > 0 ) {
obj.remove();
$( p._constant ).find( '#' + obj_id ).removeClass('selected');
} else {
$(p._constant).append( obj );
obj.removeClass( 'selected' );
ls.sort_list( p, p._constant );
obj.unbind('click');
obj.bind('click', function() {
ls.move_right( p, $(this) );
});
}
} else {
if ( obj.hasClass('selected') ) {
obj.removeClass( 'selected' );
} else {
obj.addClass( 'selected' );
}
}
// update the list array field
ls.track_selected_elements( p );
},
/* *************************************************************************
* END :::
************************************************************************* */
/* *************************************************************************
*
* Moves selected element from the contstant list to the variable list
*
************************************************************************* */
move_right : function( p, obj ) {
var p = p;
obj_id = $( obj ).attr('id');
// this object exists in the other list
// just remove it from existing list
if ( $( p._variable ).find( '#' + obj_id ).length > 0 ) {
obj.remove();
} else {
$(p._variable).append( obj );
obj.addClass( 'selected' );
ls.sort_list( p, p._variable );
obj.unbind('click');
obj.bind('click', function() {
ls.move_left( p, $(this) );
});
}
// update the list array field
ls.track_selected_elements( p );
},
/* *************************************************************************
* END :::
************************************************************************* */
/* *************************************************************************
*
* When append to the list(s), the ordering is off. This alphabetically
* sort the list items
*
************************************************************************* */
sort_list : function ( p, obj ) {
var parent = obj;
var items = $(obj + ' ' + p._clickable).get();
items.sort(function(a,b){
var keyA = $(a).text();
var keyB = $(b).text();
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
var ul = $(parent);
$.each(items, function(i, li){
ul.append(li);
});
},
/* *************************************************************************
* END :::
************************************************************************* */
/* *************************************************************************
*
* appends the list of selected LI elements in a hidden input box. will
* allow you to get the values on form post without any jquery or javascript
*
************************************************************************* */
track_selected_elements : function( p ) {
var p = p;
var ls_list_array = [];
_class = ( p._update_list ) ? '' : '.selected';
/* *******************************************
* remove the old list to null it out */
$('#ls_update_list_array').remove();
/* ******************************************
* get the complete list of selected li's */
$(p._variable + ' li' + _class).each(function() { ls_list_array.push($(this).attr('id')) });
/* *******************************************
* append the array list as an hidden input */
var ls_input = '<input type="hidden"'
+ 'id="ls_update_list_array" '
+ 'name="ls_update_list_array" '
+ 'value="' + ls_list_array + '" />'
$(p._variable).append(ls_input)
}
}
Dual List Example
- Item 1 text
- Item 3 text
- Item 7 text
- Item 8 text
- Item 2 text
- Item 4 text
- Item 5 text
- Item 6 text
Single List Eample
- Item 1 text
- Item 2 text
- Item 3 text
- Item 4 text
- Item 5 text
- Item 6 text
- Item 7 text
- Item 8 text
