Wednesday, March 19, 2008

An HTML checkbox that submits when unchecked.

I call this... The Fake Checkbox!   :)

See, the problem is a normal HTML checkbox only submits to the server when it's checked. If it's unchecked, nothing gets sent to the server. Sometimes I want a value (like, umm, false?) sent to the server whether it's checked or unchecked.

So how do we go about making a checkbox that does this? The idea is simple -- make a normal checkbox with Javascript attached to it that updates a hidden input field when checked or unchecked.

Making a Rails helper to do this is simple -- put this in application_helper.rb.

    1 def fake_check_box_tag(name, checked_values, is_checked, html_options = {})
    2   onchange        = html_options[:onchange] || ""
    3   checked_value   = checked_values[:checked] || 'true'
    4   unchecked_value = checked_values[:unchecked] || 'false'
    5   unique_id       = rand.to_s[-5, 5]
    6   poser_id        = "fake_check_box_poser_#{unique_id}"
    7   value_id        = "fake_check_box_value_#{unique_id}"
    8   onchange        = onchange + "; doFakeCheckBoxClick(this, #{unique_id}, '#{checked_value}', '#{unchecked_value}')"
    9   
   10   html_options.delete(:object_id)
   11   html_options[:onchange] = onchange
   12   html_options[:id] = poser_id
   13   
   14   html = ''
   15   html += hidden_field_tag  name, is_checked ? checked_value : unchecked_value, :id => value_id
   16   html += check_box_tag     nil, 'true', is_checked, html_options
   17   html
   18 end

Then you need to define this Javascript function.

    1 function doFakeCheckBoxClick(me, unique_id, checked_value, unchecked_value)  {
    2   unique_id = 'fake_check_box_value_' + unique_id
    3   if (me.checked)
    4     $(unique_id).value = checked_value;
    5   else
    6     $(unique_id).value = unchecked_value;
    7 }

Now you can call it just like almost like the Rail's built in check_box_tag method.

    1 fake_check_box_tag "person[is_female]",
    2                    { :checked   => 'yes',
    3                      :unchecked => 'no' },
    4                    true,
    5                    { :onchange => "alert('checkbox clicked!')" }

In this example, if the checkbox is checked, the following will be true in your action:

params[:person][:is_female] == 'yes'

If it isn't checked, then this will be true:

params[:person[:is_female] == 'no'

The 3rd parameter (true) says that the checkbox will initially be checked.

0 comments: