Friday, 16 March 2007

Choices list

A basic CRUD list page tends to have various ways of manipulating the content - sorting, filtering etc. Most of these apply to a single column of data, so the UI will generally end up with a button, link or other input in the column-head. I found that I often needed a list of choices where some referred to a single column and others didn't (eg "Sort by: date, popularity, controversy") or choices that have no bearing on the data at all (eg "View as: User, Moderator, Admin").

It was annoying to have to type out the HTML for these lists of choices each time, with appropriate styling to highlight the "current item" etc so I wrote up a helper. My example uses RESTful paths - but could be quickly modified for legacy paths too.

    def make_choicelist(title,fieldname,choices,path_hash)
    # creates a horizontal list displaying a set of choices the user can
    # pick from including urls for each choice.
       cur_val = params[fieldname]
       str = "<div class=\"hlist\"><span class=\"head\">#{title}</span>"
       choices.each do |label,value| 
         path = url_for path_hash.merge(fieldname => value)
         str << "<span class=\"#{(cur_val && cur_val == value.to_s) ? "current" : "item"}"
         str << "\">#{link_to_unless_current(label, path)}</span>"
       str << "</div>"

You can then pass it:

  • The title of the choice list
  • The name and current value of the field that saves the state of this item
  • The set of choices (label+value) that this field can take
  • The basic URL of the page apart from this field - as a hash (so we can merge in the new value)
   <%  choices = [["Admin", :admin],
                ["Moderator", :mod]
                ["User", :user]] -%>
  <%= make_choicelist "View as:", :user_type, choices, 
                 hash_for_widgets_path -%>

The code will generate the list with the given title, and will add each option after it - highlighting whichever is the current choice. You can pair this with your stylesheet to restyle the choice-list appropriately. A really basic style example is below:

/* used for horizontal lists - generally for depicting choices */
.hlist {
  padding: 0px;
  background-color: #EEE;
  color: #333;
  border: 1px solid #333;
/* short, descriptive heading for the list */
.hlist .head {
  padding-left: 10px;
  padding-right: 10px;
  font-weight: normal;
/* list items */
.hlist .current, .hlist .item {
  font-weight: bold;
/* the currently-selected item */
.hlist .current {
  padding: 3px;
  border: 2px inset black;
  background-color: #333;
  color: #CCC;
/* an unselected item */
.hlist .item {
  background-color: silver;
  font-weight: bold;
/* the link for an unselected item */
.hlist .item a {
  border: 2px outset black;
  color: #333;
  background-color: silver;
  text-decoration: none;
.hlist .item a:hover {
  border: 2px inset black;
  background-color: #444;
  color: #CCC;

Which will give you something that looks like this:

No comments: