Forum OpenACS Development: New "combo box" form widget

Posted by Luke Pond on
Application: when you have a list of probable values for a field, but you also must allow other values to be entered. The combo box combines a select widget with a text-input widget, which is hidden unless a particular value ("Other") is selected.

The javascript function works fine with Netscape 6.2 and IE5.5. I also tried it on Netscape 4.79 and Opera 6.01 and found it doesn't work so well there.

1. Add the following to acs-templating/tcl/widget-procs.tcl

ad_proc -public template::widget::combo { element_reference tag_attributes } {

  upvar $element_reference element

  set combo_select_element_name "$element(name)_combo"
  set combo_input_element_name "$element(name)"

  if {$element(mode) == "edit"} {
      # see if the "other" option should be selected      
      set selected_value [lindex $element(values) 0]
      set select_other_p t
      foreach option $element(options) {
	  set curr_value [lindex $option 1]
	  if {[string equal $curr_value $selected_value]} {
	      set select_other_p f
      if {$select_other_p == "t"} {
	  set selected_value "other"
      } else {
	  lappend tag_attributes "style" "visibility:hidden"

      # make sure your form template includes the javascript comboChange function!
      array set select_attributes \
	      [list onchange "comboChange(this,'$combo_input_element_name')"]

      set output [template::widget::menu \
	      $combo_select_element_name $element(options) [list $selected_value] select_attributes $element(mode)]

      # the properties of this element are divided between
      # the select and text-input widgets.   the element's name, value
      # and extra html attributes are given to the text-input
      # widget, while the select widget gets the options.

      append output " "
      append output [input text element $tag_attributes]

      return $output
  } else {      
      return [input text element $tag_attributes]
2. Add the following function to the form template file you're using:
function comboChange(s,tName) {
	var t = s.form.elements[tName];	
	if(s.options[s.selectedIndex].value == "other") {
		t.value = ""; = "visible";
	} else { = "hidden";
		t.value = s.options[s.selectedIndex].value;
3. Assuming you're using ad_form, here is an example element definition.
{title:text(combo) {label "Title"} {optional} {options {{"None" ""} {"Mr." "Mr."} {"Mrs." "Mrs."} {"Ms." "Ms."} {"Dr." "Dr."} {"Other" "other"}}}}
Hope you will find this useful!
Posted by Don Baccus on
If you define a data validation proc for your "combo" widget you can then just say "title:combo" in ad_form rather than be forced to remember that it's a select-style widget that is used with "text".  I really encourage folks to take this approach when defining new form stuff.

Also it's not that hard to track whether or not you've put out the javascript function and to put it out automatically.  This was the approach I took when defining several javascript widgets for Greenpeace.

Then you can use any of the existing form template files ...