views:

35

answers:

1

Hey all

I am having trouble updating a partial that contains a nested_attributes_for form with AJAX.

My application needs to load a new section of the form based on the event type chosen in the main form. The fields associated with each type are stored in a database table.

At the moment, when I select an event type, the id of the event type gets passed to the events controller via a remote function. (code below)

<%= event_form.collection_select :type_id, Type.find(:all, :order => "event_type"), :id, :event_type, { :prompt => 'Select Event Type' }, { :onchange => 
  remote_function(
     :url => event_specifics_events_path,
     :with => "'type=' + encodeURIComponent(value)" ), } %>

This sends my id to the controller successfully, which then searches for all fields associated with the event type id and then replaces an empty div (id of "specifics") with the partial that will contain the additional fields. (code below)

    def event_specifics
    # Catch passed variable and search for event fields by event type id
    selected_type = params[:type]

    @event_fields = EventField.type_id_equals(type)

    if @event_fields
        render :update do |fields|
            fields.replace_html 'specifics', :partial => 'event_specifics', :locals => { :event_form => event_form, :event_fields => @event_fields }
        end
    end
end

The code in my partial is as follows:

<% if @event_fields %>
<hr 100%>

<% event_form.fields_for :event_specifics do |specifics| %>
    <% for field in @event_fields %>
        <% if field.field_type == "check_box" %>
            <%=h eval "#{@specifics}.#{field.field_type} 'value', {}, '#{field.field_value}', ''" %><strong><span class="pipe"><label><%=h field.field_label %></label></strong>
        <% elsif  field.field_type == "radio_button"  %>
            <%=h eval "#{@specifics}.#{field.field_type} 'value', '#{field.field_value}'" %><strong><span class="pipe"><label><%=h field.field_label %></label></strong>
        <% else %>
            <p>
                <br /><strong><span class="pipe"><label><%=h field.field_label %></label></span><span style="color:#E81E57;">*</span></strong><br />
                <%=h eval "#{@specifics}.#{field.field_type} 'value'" %>
            </p>
        <% end %>
    <% end %>
<% end %>
<% end %>

When I try to run this, I get an error claiming

undefined local variable or method `event_form' for #<ActionView::Base:0x431b2d8>

I have tried passing the event_form builder to the url and treating it as a parameter, it then complains it cant call fields_for on a string.

the builder 'event_form' is the builder on the parent form here:

<% remote_form_for @event, :url => { :controller => "events", :action => "create" } do |event_form| %>

Does anyone have any ideas or solutions that would solve this problem? Thanks in advance!

In case it helps anyone, I am using Ruby 1.8.7 and Rails 2.3.8 with Prototype 1.6.0.3.

A: 

Ok, I have a working dynamic form now, I used javascript to build it instead. I figured I would post my solution here in case anyone stumbled upon this later.

Fetch all event fields in controllers New action:

@event_fields ||= EventField.all

In the partial, loop through all fields and group them by event type id and then loop through grouped records to build divs (the ids of which are just the event type ids the fields are associated with) containing the fields.

    <% event_form.fields_for :event_specifics do |specifics| %>
    <% test = @event_fields %>
    <% for field in @event_fields %>
        <div id="<%=h field.type_id %>", style="display:none;", class="specifics_fields">
            <hr 100%>
            <% type_fields = test.select { |t| t.type_id == field.type_id } %>
            <% for type in type_fields %>
                <% if type.field_type == "check_box" %>
                    <%=h eval "specifics.#{type.field_type} 'value', { }, '#{type.field_value}', nil" %><strong><span class="pipe"><label><%=h type.field_label %></label></strong>
                <% elsif  type.field_type == "radio_button"  %>
                    <%=h eval "specifics.#{type.field_type} 'value', '#{type.field_value}'" %><strong><span class="pipe"><label><%=h type.field_label %></label></strong>
                <% else %>
                    <p>
                        <br /><strong><span class="pipe"><label><%=h type.field_label %></label></span><span style="color:#E81E57;">*</span></strong><br />
                        <%=h eval "specifics.#{type.field_type} 'value'" %>
                    </p>
                <% end %>
            <% end %>
        </div>
    <% end %>
<% end %>

Select Box:

<%= event_form.collection_select :type_id, Type.find(:all, :order => "event_type"), :id, :event_type, { :prompt => 'Select Event Type' }, { :onchange => "myFunction(this.value);", } %>

JS Function:

function myFunction(value) {
$$('.specifics_fields').each(function(e){
    e.hide();
});
$(value).show();
}

Evenything then functions as intended and is pretty efficient. All it really requires from here is a bit of tweaking to make the div ids validate (div ids shouldn't start with a number - easy fix) and I should probably remove the test variable and move it all into a helper instead to clean up the view.

I don't really like the solution too much, but I can't see any other way, so please, if you know any better don't hesitate to suggest a new method of doing this.

Verloren