Tutorials » Select Boxes and DHTML Layers

The problem with select boxes.

A select box always stays on top of any div placed above it, even if the div has a greater z-index athough any other form element will behave correctly.

Example 1

     

above you'll find the most common form elements

Reason

The reason this happens is simple. Any HTML element can be categorized as windowed or windowless. All windowless controls will follow the z-index structure set in place for them. While windowed controls will still follow a z-index. They follow their own order of things. A windowless control will never overlap a windowed control because it's z-index is not comparable to that of a windowed control.

So the question is why did Microsoft make the select box windowed. Is there a valid reason?
I've taken a good hard look and there is no obvious reason why the select box was made windowed. DHTML might not have been around when select elements were first introduced. Microsoft is quick enough to state the problem, but have yet to offer us a valuable solution. Interestingly enough, in VB when you create custom controls you get an option to create the control as windowed or windowless. Both will function equally as well in a web environment.


The solution - you've been waiting for

Lets re-create example 1 except this time the select box will be correctly obscured by the div.

Example 2

     

above you'll find the most common form elements


THE VERDICT

If something about that select box looks different it is because it is not a select element at all. Thankfully it's not a custom control that I created either. This control requires no download of any kind. Even better, this control is part of the windows operating system. It is the same control you use day after day in your windows applications.

Its called the Microsoft Forms combo box control. Mostly used in visual basic applications, it works on the web just fine and everyone running windows is compatable.

Just the facts - let's get back to the look of this control.

Lets begin by illustrating the customizability of this control.( looks only for now)

A very big one
A very small one

A 3d control     Coloring is also possible.

There are a lot of combinations regarding the look of this control. You can change its colors, borders, font, border color, mouse cursor; just about everything imaginable. It also supports CSS. That's right, you can attach inline style attributes to this control.

Special effects - might be useful to your design.

This control may very well add an original feel to your site. - take a look at the examples below

 This one has no button.(This is not a text element)

   This ones button becomes visible when you click the control.

   This ones button does not have an arrow.

   Three Dots.

   Two Dots

Later you can play around with all the many combinations of looks for this control.

Just the facts - how it works and how to implement it.

The code for the control is listed below - don't worry about how you'll populate the control at this stage or how you'll post, etc. as all will be explained in good time. This code below may look like a lot but I can assure you you'll get used to it and the benefits are great. Just replace your <select> tag with this code

<object classid="clsid:8BD21D30-EC42-11CE-9E0D-00AA006002F3" id="" name="" width="100" height="20"> the class id remains the same never change this
<param name="VariousPropertyBits" value="746604571">  
<param name="BackColor" value="16777215"> Style equivelant to background color='color' - note : this color is in decimal notation not hex (being a range from 000000 - FFFFFF) use calc.exe to convert from hex to dec.
<param name="ForeColor" value="2147483656"> Foreground color of text
<param name="MaxLength" value="0"> Like maxlength in a text box / applicatable only when you set the display style property to accept user input - see below
<param name="BorderStyle" value="2"> 2d / 3d / more border options
<param name="ScrollBars" value="0"> You'll notice the lists have scroll bars - you can turn them on / off here - both vertical and horizontal are supported
<param name="DisplayStyle" value="7"> VERY IMPORTANT - Use this setting to turn user input off. When this is set to 7 , It behaves like a select box. Remember it is after all a combo( combination between a text and list box) box
<param name="MousePointer" value="1"> Like style="cursor:cursor" - a numeric value expected
<param name="Size" value="2540;635">
<param name="PasswordChar" value="0">
<param name="ListWidth" value="4000"> Unlike select elements - this control has a width you can set for your list items that drop down. Handy when displaying very short or very long list items.
<param name="BoundColumn" value="1">
<param name="TextColumn" value="65535">
<param name="ColumnCount" value="1">
<param name="ListRows" value="8"> Perhaps the number of list rows available before scrolling occurs - plausable guess?
<param name="cColumnInfo" value="0">
<param name="MatchEntry" value="1">
<param name="ListStyle" value="1"> This is a nice feature add list rings similar to having a <li> command in every list item . You can play and configure for all the options.
<param name="ShowDropButtonWhen" value="2"> The button on the side need not be visible all the time - you can customize it here
<param name="ShowListWhen" value="1"> Show / hide the list when you decide - play around a bit might make more sense
<param name="DropButtonStyle" value="1"> You can make the button plain / dots / arrow using this feature
<param name="MultiSelect" value="0"> Select more than one option at a time.
<param name="Value" value>
<param name="Caption" value>
<param name="PicturePosition" value="458753">
<param name="BorderColor" value> Adjust the color of the border here
<param name="SpecialEffect" value="3"> I'll let you discover this one - it changes the way you interact / view the control
<param name="Accelerator" value="2">
<param name="GroupName" value>
<param name="FontName" value="Arial">
<param name="FontEffects" value="1073741824">
<param name="FontHeight" value="150">
<param name="FontOffset" value="0">
<param name="FontCharSet" value="0">
<param name="FontPitchAndFamily" value="2">
<param name="ParagraphAlign" value="1">
<param name="FontWeight" value="200">
</object>

I would also like to add at this point that a great deal of these params are optional and once you find the configuration that suits you, you can disregard a lot of these tags.

Naming the control

With a select box you need not specify the id, however with the combo box control it is nessessary to specify both the name and the id of the control. The reason for ths is that you will need to referrence the control by id when assigning events to it.

Populating the control using VBScript (JavaScript will work just as well).

So how do we populate the control? You need to create a short script to populate the combo.

Here are a few population examples assuming a combo box object is placed within the form tags of a form named 'form1' and the combo has a name of 'combo' and an id of 'combo':

<script type="text/vbscript">
form1.combo.additem("item one")
form1.combo.additem("item two")
</script>

 ' asp population example from a recordset
<script type="text/vbscript">

<% while not rs.eof %>

form1.combo.additem("<%= rs("name") %>")

<%
rs.movenext
wend
%>

<script>

The scripts are always placed after the object. A script error will occur if it tries to reference your control before it is created

Most of you more advanced users must have some questions at this stage. The two that I know you must be thinking are

Lets start with the first question. Obviously both these questions have valid answers or else I would not consider using the forms control. It also occurred to me that the following sections might seem much more complicated than they really are. Just keep a clear head and build the control in slowly to your design. Then advance step by step untill you've mastered all of the required scripts.

Selecting an item from the list is easy - let's review a static script and then an ASP example.

<script type="text/vbscript">
form1.combo.additem("item one")
form1.combo.additem("item two")
form1.combo.listindex = 1 <!-------- heres the line that selects -->
</script>

This will select the second item in the list and populate the combo. Note two things: the index count starts at zero (0), and importantly: there is no need to use the text property of the combo.

The ASP example: you want to select a client based on request.form("clientid")

<script type="text/vbscript">
x = 0
<% while not rs.eof %>

form1.combo.additem("<%= rs("clientname") %>")

<% if request.form("clientid") = rs("clientid") then %>

form1.combo.listindex = x

<% end if %>

x = x + 1

<%
rs.movenext
wend
%>

</script>

Now for the interesting and final part - passing the value and not the display name with the form.

I've done a fair bit of research into the likes of the combo box. In visual basic you can simply pass the values through using the item data property. However I have tried this while the combo is embedded in a web page and I didn't get this to work. So I came up with a work around.

The theory is simple - populate the combo from a recordset or static list, displaying only the friendly names in the combo and in the same loop creating an array with the values you really want to pass through the form. The array and the friendly names are linked by their indexes in either the array or the combo box.

eg: let's say you have the following list.

Clientid Client Name
 1 Mary Smith
 2 James Jackson
 3 Dick Helen

Array Index Client id Combo box listindex Client name
0 1 0 Mary Smith
1 2 1 James Jackson
2 3 2 Dick Helen

<form action="script.asp" method="post" name="form1">

<input type="hidden" value="" name="true_clientid">

<!-- cod for the combo box-->

<object classid="clsid:8BD21D30-EC42-11CE-9E0D-00AA006002F3" id="combo" name="combo" width="100" height="20">
<param name="VariousPropertyBits" value="746604571">
<param name="BackColor" value="16777215">
<param name="ForeColor" value="2147483656">
<param name="MaxLength" value="0">
<param name="BorderStyle" value="2">
<param name="ScrollBars" value="0">
<param name="DisplayStyle" value="7">
<param name="MousePointer" value="1">
<param name="Size" value="2540;635">
<param name="PasswordChar" value="0">
<param name="ListWidth" value="4000">
<param name="BoundColumn" value="1">
<param name="TextColumn" value="65535">
<param name="ColumnCount" value="1">
<param name="ListRows" value="8">
<param name="cColumnInfo" value="0">
<param name="MatchEntry" value="1">
<param name="ListStyle" value="1">
<param name="ShowDropButtonWhen" value="2">
<param name="ShowListWhen" value="1">
<param name="DropButtonStyle" value="1">
<param name="MultiSelect" value="0">
<param name="Value" value>
<param name="Caption" value>
<param name="PicturePosition" value="458753">
<param name="BorderColor" value>
<param name="SpecialEffect" value="3">
<param name="Accelerator" value="2">
<param name="GroupName" value>
<param name="FontName" value="Arial">
<param name="FontEffects" value="1073741824">
<param name="FontHeight" value="150">
<param name="FontOffset" value="0">
<param name="FontCharSet" value="0">
<param name="FontPitchAndFamily" value="2"> <param name="ParagraphAlign" value="1">
<param name="FontWeight" value="200">
</object>

<!-- Now create the population script. The array is also generated here.-->

<script type="text/vbscript">

' the counter variable. keeps track of your array size and the script wont work without it.
x = 0

' note: the brackets are what define the array - the empty set
' means that the initial size of the array has not been
' defined - this we will do later.
dim client_array()

<% while not rs.eof %>

' extend the size of the array by one - because x increments by one.
redim preserve client_array(x)

' now give the newly defined space a value - this is the clientid not the name.
client_array(x) = <%= rs("clientid") %>

' populate the combo now with x being the listindex of the combo at any given point in the loop.
form1.combo.additem("<%= rs("client_name") %>")

' inc x - this is important make sure x gets incremented in the loop
x = x + 1

<%
rs.movenext
wend
%>

</script>

Now we have an array called client_array and a combo called 'combo'. The array stores the clientid and the combo the client name. The index is the common bond between them.
For example, 'client_array(3)' holds the id for the client with the name 'form1.combo.listindex(3)'.

Finally we need to populate the hidden form element because the array is not submitted with the form. To do this we need to assign an event to the combo box so that whenever the combo box changes the hidden form element gets updated from the array.

Here is the script to do this.

<script type="text/vbscript">
 ' note: not onchange or onclick - its just change or click.
function combo_change()
form1.true_clientid.value = client_array(form1.combo.listindex)
</script>
</form>

Simple yet effective. Now when you submit the form you get the name and id.

An important note: if you are selecting an item in the list based on request.form, the box will be selected. If the user decides not to reselect another item from the list and instead just re-submits the form, the value of 'true_clientid' will be null because the change event for the combo was not processed. To counteract this issue, just assign the 'true_clientid' a value when you select the item in the combo.

Also be aware that these controls have a way of retaining the focus. So when you select an item in the combo and then press submit, you will find nothing will happen. To counteract the need to double click the submit, try this:

function combo__change()
 ' your script here
 ' submit being the name of your submit button

form1.submit.focus()

end function

Basically do something to get the focus away from the control once an action has occurred. If you are using a submit button without a border you might have a small problem, unless you have a text element after the control you can move the focus to.

About the author - Jeremy Leppan can be reached at the following email address:  mjleppan@hotmail.com