简体   繁体   中英

Rails 4 rendering a partial with ajax, jquery, :remote => true, and respond_to

It seems like rendering a page dynamically with AJAX in response to a submitted form is common. None of the other similar questions are focused around how to do this in a general way.

The best blog post I could find on the subject was here: http://www.gotealeaf.com/blog/the-detailed-guide-on-how-ajax-works-with-ruby-on-rails

The question: How do I code my rails application so that I can trigger a partial view to load via AJAX when I submit a form or click a link?

Several things must be present for this to work, including the :remote => true flag on the triggering element, the respond_to :js flag in the controller's class definition, the route, the partial view, and lastly the jquery to actually render a dynamic partial must be contained in a separate .html.js file.

Examples below are for a fictitious "render_partial_form" method of the "someajax" controller.


1) Add a :remote => true flag to the triggering element
put the :remote => true flag on the link or form tag in your .html.erb file (view) for the element that you want to trigger the AJAX call, like

<%= form_tag("/someajax", method: 'post', :remote => true) do %>

with :remote => true, rails will not automatically switch views, which allows the JQuery to be run instead. This can be used with a form_tag, a link_tag, or other types of tags.


2) Add "respond_to :html, :js" at the top of the controller

At the top of your controller's class definition, you must now specify that the controller can respond to javascript as well as html:

class SomeajaxController < ApplicationController
   respond_to :html, :js

   ...

   def render_partial_form
      @array_from_controller = Array.new

      ...

   end
end

In this example, there's a variable being passed from the controller into the view: an array of select list options called @array_from_controller .


3) Route the http verb to your controller's method

Since I wanted a POSTed form to trigger the AJAX call, I routed the post verb for my controller to the render_partial_form view.

post 'someajax' => 'someajax#render_partial_form

The controller method defined by def render_partial_form matches with the name of the view, _render_partial_form.html.erb so there is no need to call a render action from the controller.


4) Create the partial view
The partial view should have the same name as your controller method and begin with an underscore: _render_partial_form.html.erb

<h3>Here is the partial form</h3>

<%= form_tag("/next_step", method: 'post') do %>
    <%= label_tag(:data, "Some options: ") %>
    <%= select_tag(:data, options_for_select(@array_from_controller.transpose[0].collect)) %>
    <%= submit_tag('Next') %>
<% end %>


5) Create the JQuery file

JQuery statements trigger the form's rendering. Replace "render_partial_form" with the actual name of your controller method and partial view. The slideDown effect is optional "eye candy". Create a file with a .js.erb extension, and the same name as your controller:

render_partial_form.js.erb

$('#render_partial_form').html("<%= escape_javascript (render partial: 'render_partial_form') %>");
$('#render_partial_form').slideDown(350);

You should use JS views (which have "js.erb" extension), something like "create.js.erb" for create controller action. Then, add format.js to the respond_to do |format| ... end respond_to do |format| ... end block. And add remote: true parameter to your form. Notice: js.erb should include Javascript code you need to be included, like:

$("tbody#items").append("<%= j render(partial: 'your_partial_path') %>")

For what it's worth (because I was tripping up on this in an app upgrade from Rails 2 to 3): you can also do it by adding an event handler that appends the returned HTML, like the old Rails 2 prototype library used to do.

If, for instance, you're trying to take this (prepare for a runon sentence):

form_remote_tag url: {...}, update: ...

Where the response is coming in as HTML and being appended automatically, and replace it with this:

form_tag {...}, remote: true

By adding an event handler to your application.js file that simply does the same thing, appending the content to a specific element, like this:

$("#myform").on('ajax:success', function(e, data, status, xhr) {
  $("#container").append(data);
)};

Then... you may run into the same problem I did, which was that it never fires the ajax:success event! The problem is that it's expecting JS or text in the response, but it's getting HTML. The way to fix that is to tell it that the response will be HTML using an attribute on the form tag:

form_tag {...}, remote: true, data: {type: :html}

Piece of cake!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM