Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I do AJAX-y conditional show/hide form fields in Rails?

I'd like to show or hide a few fields in a form in Rails, depending on the state of a select field in the form. I don't (currently) need a second database lookup for the fields, so I'm trying to keep it all confined to the view. I have the outline sketched out, but I'm having some trouble with the implementation details.

My initial thought was to use observe_field and call Element.show etc. etc., but then I'd have to write a Javascript conditional. This will probably have to work, but I want to avoid it if I can.

Another approach would be to use observe_field to request a RJS template, and replace_html to insert the fields. Not bad, but since I'm using a form_for block I'd either have to pass the form instance all the way through the RJS template to do it right.

I could also update the record on each pass, and display the form under the new conditions, but that's what I'm trying to avoid. It'd be so much simpler to just do this all in the view.

What am I missing here? What's the accepted practice for conditional show/hide forms in Rails?

like image 459
scottburton11 Avatar asked Feb 05 '09 03:02

scottburton11


3 Answers

As a rails developer, I suggest adhering to the principles of unobtrusive javascript. When it comes to rails, what this usually means is that you shouldn't just write one big view to handle all your functionality. This makes your HTML view easier to develop and maintain, it makes your behavior easier to maintain, and it usually leads to a better understanding of exactly what your application is doing. To that extent, I avoid rails javascript helpers at all costs.

What I would do is split off your behaviour into a javascript file that you code yourself. Using a library such as jquery (my favorite for this sort of thing is lowpro, but I'll be the first to admit to being a bit set in my ways), it's pretty easy to attach an event handler to specific elements (or to a whole class of elements at once).

For a select box, an onChange handler will get fired when the user changes the selection. the selectedIndex property on the element will tell you which option is selected, and the options array will let you look up the associated option. So, in your handler you could do something like the following (using prototype):

function(e) {
  var element = Event.element(e)
  var index = element.selectedIndex
  var option = element.options[index]

  if(option.value == "Show fields")
    $('hidden-fields').show()
  else
    $('hidden-fields').hide()
}
like image 193
Christopher Swasey Avatar answered Nov 16 '22 11:11

Christopher Swasey


I handle the same thing a few different ways:

<%= link_to_function( check_box_tag "model[attribute_name]" ) do |page| 
    page.toggle :model_attribute_name
end-%>

<span style="display:none;" id="model_attribute_name">  
<%= f.text_area :other_conditional_attribute -%>  
</span>

or

<%= link_to_function "Conditional Item", :class => "your-style-class" do |page| 
    page.insert_html :bottom, :other_conditional_attribute, :partial => 'conditional_attribute_partial', :object => Object.new, :locals => {:local_variable => local_variable}
end-%>

The rjs stuff/prototype helpers are awesome.
Rails API: PrototypeHelpers
Rails API: JavascriptHelpers

like image 42
inkdeep Avatar answered Nov 16 '22 11:11

inkdeep


I would suggest using a simple JQuery function along the lines of:

$('a#slick-show').click(function() {
    $('#slickbox').show('slow');
    return false;
  });

For the basics of show/hide in Jquery, there is a tutorial here.

like image 1
Serx Avatar answered Nov 16 '22 11:11

Serx