Extended: Forms with widgets

February 14th, 2008Posted by benediktFiled in Articles, Javascript

There is a great article by Jason Long on Vitamin called ‘Streamline your forms with widgets’. In his article Jason Long describes a nice looking way to clean up a lot of checkboxes into multiple dropdown widgets. What I really liked was the idea to have some summary about the selected items next to the title of the dropdown widgets. Unfortunately he didn’t implement the updating function but just mentioned it as a possible extension. In addition he pointed out that “Any Fuel” would be much easier to read than “Fuel (Gasoline, Diesel, Alternative)”. As I was in the right mood for some Javascript I implemented the missing functionality.

At first I added four little lines to the top of the toggleDropdown() function. This little snippet checks weather the panel is currently visible (so the function was toggled to hide the panel again) and calls the updateTitle() function.

   1  function toggleDropdown(panel) 
   2  {
   3    panel = $(panel);
   4    if(panel.visible()) {
   5      updateTitle(panel);
   6    }
   7  
   8    // toggle the requested one
   9    Element.toggle(panel);
  10       
  11    // then hide all of the others so that only
  12    // one (at most) is open at a time
  13    $$('body .dd_option_panel').each(function(node){
  14      if (node != $(panel)) {
  15        Element.hide(node);
  16      }
  17    });  
  18  }

To do the actual updating of the title I used Prototype’s nifty little DOM traversal toolkit. It provides methods such as Element#select(), Element#up(), Element#down(), Element#previous() and Element#next(). All of can be supplied with a selector, similar to those in CSS.

First I select all child elements of type “input” and check their value. If the value matches “on” the checkbox is selected and I travel down to the next “label”-element to push it’s content into an array. Afterwards I check the size of this array and decide how to change the title. If none of the checkboxes are selected I add “No ” to the title and don’t display the list of the selected values. Accordingly if all are selected I prepend “Any ”. Otherwise I leave the title as it is and update the list behind it by joining the elements of the array into a string. To prevent titles such as “Any Any No Any Fuel” I clean up the title by removing either Any or No in front of the title using String#gsub().

   1  function updateTitle(panel)
   2  {
   3    selected = new Array();
   4    panel.select('input').each(function(box){
   5      if(box.getValue() == 'on') {
   6        selected.push(box.next('label').innerHTML);
   7      }
   8    });
   9       
  10    inner = panel.previous(".inner");
  11    title = inner.innerHTML.gsub(/^([Any|No])/, '');
  12    
  13    if(selected.length == 0) {
  14      inner.update('No ' + title);
  15      inner.down(".light").update('');
  16    } else if(selected.length == panel.select('label').length) {
  17      inner.update('Any ' + title);
  18      inner.down('.light').update('');
  19    } else {
  20      inner.update(title);
  21      inner.down('.light').update('(' + selected.join(', ') + ')');
  22    }
  23  }

In order to get correct titles right from the beginning I update all titles after the page loaded.

   1  Event.observe(window, 'load', function(event) {
   2    $$('body .dd_option_panel').each(function(panel) {
   3      updateTitle(panel);
   4    });
   5  });

That’s it! Click here to see the changed example.

Of course all the credits for the original implementation, graphics, and idea go to Jason Long.

Leave a Reply