Select box replacement
Careful! This post is looking a little old and could be inaccurate in many, many ways
Many form elements can look pretty ugly, and although their consistent look helps identify their purpose to the user it’s also sometimes fun and useful to break the conventions. One element that is hard to change is the select box, mainly due to IE not implementing any CSS for select boxes, yet as the image shows below, I decided to try something a little more radical.
What the image shows is a small part of a site that is not yet live, and specifically it shows a select box transformed. Rather than showing a standard select box I foolishly designed a form element that with the aid of two buttons you would move up and down the options incrementally.
Why?
This form is a central element of the design of the site and I wasn’t content in putting in any standard form elements without styling them. The select boxes also only contained 5 or 6 options so were not long lists to move through one by one. So I came up with a solution that would present a set of options most commonly displayed in a select box in a more visually pleasing way.
How?
As the next image shows the form does exist with standard select boxes visible, this is in fact the non JavaScript version of the page. Although I didn’t think so much about the implementation at the design stage I was conscious that the form still work for those without JavaScript when I came to building it.
Initially it appeared I’d set myself a rather complex challenge and had considered creating the non JavaScript version in HTML and hiding it with CSS. However I had to ensure that the form submitted both versions of the form via the same select box. This coupled with the fact the options already existed in the select box it seemed wise to create all the alternative select box completely using JavaScript.
In a nutshell the JavaScript collects all the information from the select box and constructs what is visible to the user. When the user then changes the option the now hidden select box also changes so that the visible option is submitted correctly to the form.
Code
So below is the code I’ve built to do all this. I’ve added some comments to ensure it’s easy to understand as I’m sure it’s not the cleanest code known to developer kind. By the way when I said JavaScript I meant JQuery as to me it’s the same thing these days.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
$(document).ready(function(){ change_select('a_selectbox_id'); }); function change_select(id){ // Get the current selected option of the select box var curr = $('#'+id).val(); // Get all the available options of the select box var ops = jQuery('#'+id+' option').map(function(){return jQuery(this).val();}).get(); // Hide the select box $('#'+id).hide(); // Add a new div container for the alternative select box $('#'+id).parent().append('<div id="'+id+'_nav"></div>'); // Add a backwards link and opening uunordered list for the options $('#'+id+'_nav').prepend('<a id="'+id+'_backward" class="select_backward">Back</a><ul class="select_nav">'); // Loop through all the options and output into the unordered list $.each(ops, function(intIndex, objValue){ $('#'+id+'_nav ul').append($( "<li>" + objValue + "</li>" )); }); // Close the list and add a forward link $('#'+id+'_nav').append('</ul><a id="'+id+'_forward" class="select_forward">Forward</a>'); // Hide all the list items $('#'+id+'_nav li').hide(); // Show the option that matches the currently selected option of the original select box $('#'+id+'_nav li:contains(' + curr + ')').show(); // If the selected option is not the first of the list bind a click event to the backward link, otherwise add a class for CSS styling if($('#'+id+'_nav li:visible').text() != $('#'+id+'_nav li:first-child').text()){ $('#'+id+'_backward').bind('mousedown', function(){movebackward(id)}); }else{ $('#'+id+'_backward').addClass('backward_disabled'); } // If the selected option is not the last of the list bind a click event to the foward link, otherwise add a class for CSS styling if($('#'+id+'_nav li:visible').text() != $('#'+id+'_nav li:last-child').text()){ $('#'+id+'_forward').bind('mousedown', function(){moveforward(id)}); }else{ $('#'+id+'_forward').addClass('forward_disabled'); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function moveforward(id){ // Find the currently visible options var currvis = $('#'+id+'_nav li:visible'); // Show the next option in the list $(currvis).next('li').show(); // Hide the old current option $(currvis).hide(); // Get the text of the current visible option var newcurr = $('#'+id+'_nav li:visible').text(); // Make the current visible option of the alternate select box the actual selected option of the hidden select box $('#'+id).val(newcurr); // If current item is the last of the list unbind the click event and add a CSS class, if not and is already disabled add a bind event and remove the CSS class if($('#'+id+'_nav li:visible').text() == $('#'+id+'_nav li:last-child').text()){ $('#'+id+'_forward').unbind('mousedown'); $('#'+id+'_forward').addClass('forward_disabled'); }else if($('#'+id+'_backward').is(".backward_disabled")){ $('#'+id+'_backward').bind('mousedown', function(){movebackward(id)}); $('#'+id+'_backward').removeClass('backward_disabled'); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
function movebackward(id){ // Find the currently visible options var currvis = $('#'+id+'_nav li:visible'); // Show the previous option in the list $(currvis).prev('li').show(); // Hide the old current option $(currvis).hide(); // Get the text of the current visible option var newcurr = $('#'+id+'_nav li:visible').text(); // Make the current visible option of the alternate select box the actual selected option of the hidden select box $('#'+id).val(newcurr); // If current item is the first of the list unbind the click event and add a CSS class, if not and is already disabled add a bind event and remove the CSS class if($('#'+id+'_nav li:visible').text() == $('#'+id+'_nav li:first-child').text()){ $('#'+id+'_backward').unbind('mousedown'); $('#'+id+'_backward').addClass('backward_disabled'); }else if($('#'+id+'_forward').is(".forward_disabled")){ $('#'+id+'_forward').bind('mousedown', function(){moveforward(id)}); $('#'+id+'_forward').removeClass('forward_disabled'); } } |
The Problem
Currently there is one issue to the function, this being the following line:
1 |
$('#'+id+'_nav li:contains(' + curr + ')').show(); |
Because the JavaScript uses the JQuery function ‘contains’ it would show not only the option ‘1’ if it existed but also any other option with a 1 in it, for example ’10’. I’ve yet to find a workable solution so if you can think of something add a comment below and I’ll give it a go.