daveomcd
daveomcd

Reputation: 6555

Rails 4: How do I do an AJAX call on nested forms?

I'm trying to set up my form so that when the user changes the "position" drop down box selection it will update a partials with records that are related to that position. I will do my best to include all relevant code below with the error shown first. If I've forgotten to include anything please let me know, thanks.

Error (from the... jqXHR.responseText)

AJAX Error: NameError in Players::Reports#update_position_specifics

Showing ../app/views/players/reports/update_position_specifics.js.erb where line #2 raised:
undefined local variable or method `f' for #<#<Class:0x007f9b82ebdcf8>:0x007f9b82fc8030>

reports.coffee

  $(document).on 'change', '#report_position_id', (evt) ->
    $.ajax 'update_position_specifics',
      type: 'GET'
      dataType: 'script'
      data: {
        position_graded_id: $("#report_position_id option:selected").val()
      }
      error: (jqXHR, textStatus, errorThrown) ->
        console.log("AJAX Error: #{jqXHR.responseText}")
      success: (data, textStatus, jqXHR) ->
        console.log("Dynamic position select OK!")

_form.html.erb

<%= simple_form_for([@player, @report], html: {id: 'report-form'}) do |f| %>
  <%= f.association :position, selected: @position_graded.id %>
  <div id="position_specifics"> 
    <%= render 'form_position_specifics', f: f %>
  </div>
<% end %>

_form_position_specifics.html.erb

<%= f.nested_fields_for :evaluations,
      f.object.evaluations.target.sort_by! { |a| a.skill.order_by },
      wrapper_tag: :tr, wrapper_options: { class: 'fields' } do |fn| %>
     <% # Form fields here... %>
<% end %>

update_position_specifics.js.erb

$("#position_specifics").empty().append("<%= escape_javascript(render partial: 'form_position_specifcs', f: f") %>")

reports_controller.rb

def update_position_specifics
  # remove previous/existing position specific skill from evaluations
  @report.evaluations.joins(:skill).where(skills: { type: 'position specifcs'}).delete_all

  # add new position specifics from specified position
  @skills = Skill.joins(:positions).where(position_id: @position_graded.id)

  # Add new evaluations to report
  @skills.joins(:positions).where(positions: {id: @position_graded_id}, disabled: false).each do |skill|
    @report.evaluations << Evaluation.new(skill_id: skill.id
  end

end

Upvotes: 2

Views: 554

Answers (1)

Jay-Ar Polidario
Jay-Ar Polidario

Reputation: 6603

Updated Answer

views/posts/new.html.erb

<%= form_for(@post, id: 'myform') do |f| %>
  <%= f.association :pictures do |ff| %>
    <% target = "picture-#{ff.object.id}-div-that-will-updated" %>

    <%= ff.select :category, 'data-target': target %>
    <%= ff.file_field :file %>

    <!-- This is the element that will be updated when <select> above is changed -->
    <div id='<%= target %>'></div>
  <% end %>
<% end %>

javascripts/posts/new.js

$('#myform').find('select').change(function() {
  // get the data-target of the <select>, then load that target element with the new partially loaded (current url) target element
  $( '#' + $(this).attr('data-target') )
    .load( window.location.href + ' #' + $(this).attr('data-target') );
    // Take note of the space in ' #' above
}

In summary, what this all will do is when a user selects from a dropdown, the page is just reloaded. But instead of reloading the whole page, only the data-target element is updated. This also works for multiple nested associated records on the page.

Upvotes: 1

Related Questions