We all know those dropdown lists which are connected to each other. Select a value in one dropdown and the other gets updated according to the previous selection.
This article will explain you the best practice to achieve just that. As a goodie the solution will be fully ajaxed.
Problem summary
Lets assume we have a huge list of articles in our database and want to offer a convenient selection in one of our applications. Providing a simple dropdown which lists all articles would be too common as it would load all the thousands of articles in one long list. What we're going to do is create a second dropdown which allows us to select the articles category first and then load the articles according to its selection.
Solution
We will use the articles of ajaxed.org for this example ;) Here we have a view called
active_articles
which holds all the current articles and a
category
table which contains all our categories. Connecting them together is as easy as this..
<!--#include virtual="/page.asp"-->
<!--#include virtual="/ajaxed/class_dropdown/dropdown.asp"-->
<%
set page = new AjaxedPage
page.draw()
sub drawCategoryDD()
with new Dropdown
.datasource = "SELECT * FROM category ORDER BY catname"
'we use the category name as a value and as a caption
.dataTextField = "catname"
.dataValueField = "catname"
.name = "cat"
.commonFieldText = "-- category --"
'the "no category" item should have a blank value
'as by default its 0
.commonFieldValue = ""
.attributes = "onchange=""ajaxed.callback('articlesDD', 'articles')"""
.draw()
end with
end sub
sub pagePart_articlesDD()
with new Dropdown
set .datasource = db.getUnlockedRS( _
"SELECT * FROM active_articles WHERE category = '{0}' ORDER BY title", _
page.RF("cat") _
)
.dataTextField = "title"
.dataValueField = "id"
'we disable the articles if we have no selected category
.disabled = page.RFT("cat") = ""
.commonFieldText = "-- article --"
.name = "article"
.draw()
end with
end sub
sub main() %>
<form id="frm">
<div><% drawCategoryDD() %></div>
<div id="articles"><% pagePart_articlesDD() %></div>
</form>
<% end sub %>
Run this code — dropdowns.asp
That was easy. Our code looks nice and everything is done on the server side. What we just did is we created two dropdowns using the
Dropdown
class and rendered them onto our page. The second dropdown (the one with the articles) has been put into a pagepart (
pagePart_articlesDD
) so it can easily be called using our ajaxed pagepart technique.
What happens within
pagePart_articlesDD
is the selection of all articles according to the selection of the category dropdown (see
drawCategoryDD
procedure). We grab the selected category from the post variables using
page.RF("cat")
and use it within our where clause. Last but not least we disable the articles dropdown if no category has been selected.
Note: Both dropdowns are using different datasources. The category uses a string and the artciles dropdown uses a recordset. Why? The reason for that is that we want to use a parametrized SQL-query for the articles as we want to prevent SQL-Injection. You could solve that using string concatenation but that would be vulnerable.
In a perfectly normalized database you would rather use an ID for the category and parse the form variable using page.RFP()
into a number.
Oh, almost forget the change event. Have a look at the
attributes
property of our category dropdown. There you find a javascript call to
ajaxed.callback()
which reload our pagepart (Reminder: as we have a form with the id
frm
all form fields are passed as post variables to the callback automatically).
Pimp it! Lets give the dropdowns a bit of style
The problem has been solved but I would like to outline some features of the
Dropdown
class at this point. With only some modifications we are able to do some cool stuff. Lets do the following:
- Allow a user friendly multiple selection of articles
- Highlight the "News" category
- Style it nicely so it looks like an article selection control
<!--#include virtual="/page.asp"-->
<!--#include virtual="/ajaxed/class_dropdown/dropdown.asp"-->
<%
set page = new AjaxedPage
page.draw()
sub drawCategoryDD()
with new Dropdown
.datasource = "SELECT * FROM category ORDER BY catname"
'we use the category name as a value and as a caption
.dataTextField = "catname"
.dataValueField = "catname"
.name = "cat"
.commonFieldText = "-- category --"
'the "no category" item should have a blank value
'as by default its 0
.commonFieldValue = ""
.attributes = "onchange=""ajaxed.callback('articlesDD', 'articles')"""
'create an event handler to highlight the news item
.onItemCreated = "onCategory"
.draw()
end with
end sub
sub onCategory(it)
'if the items value is news we make it bold and red
if it.value = "News" then it.style = "font-weight:bold;color:#f00"
end sub
sub pagePart_articlesDD()
with new Dropdown
set .datasource = db.getUnlockedRS( _
"SELECT * FROM active_articles WHERE category = '{0}' ORDER BY title", _
page.RF("cat") _
)
.dataTextField = "title"
.dataValueField = "id"
'we disable the articles if we have no selected category
.disabled = page.RFT("cat") = ""
.commonFieldText = "-- article --"
.name = "article"
.cssClass = "articles"
'enable convenient multiple selection
.multiple = true
.multipleSelectionType = DD_SELECTIONTYPE_MULTIPLE
'we need the height if multiple is turned on
.size = 80
.draw()
end with
end sub
sub main() %>
<style>
#articleSelection {
border:2px inset #ccc;
background:#eee;
padding:0.5em 1em;
width:300px;
}
.articles {
overflow:auto;
white-space:nowrap;
margin-top:1em;
}
</style>
<form id="frm">
<div id="articleSelection">
<div><% drawCategoryDD() %></div>
<div id="articles"><% pagePart_articlesDD() %></div>
<div>
</form>
<% end sub %>
Run this code — dropdown_pimped.asp
Looks not so bad but I am sure some designers could make it better.
Anyway, what we just did is hooked up an event handler for the categories dropdown. That was necessary to style a specific item (in our example the news item). Furthermore we made the articles dropdown appear as a multiple dropdown by turning on its
multiple
property. Just this change makes the dropdown render as a conventional multiple select tag, but we control the multiple selection with the
multipleSelectionType
property. This provides the ability to select multiple items using a checkbox and a single item using a radio button. Thats much more user friendly I guess. Play around with it - you will like it.
Last but not least we added some style section to get a appearance. Just have a look at the produced XHTML if you want to style your dropdown. You will get an idea of how to style it quickly.
Tip: You can even create dropdowns with a one-liner. Check the getNew()
method for that. You could use it as follows:
Renders a month dropdown with one line:
(new Dropdown)(lib.range(1, 12, 1), "month", month(date())).toString()