Display inline errors with simple_form in a Bootstrap Ajax modal

蓝咒 提交于 2019-11-30 07:37:58

问题


I've found similar StackOverflow questions here and here but still can't get this to work.

I'm using Rails 3.2.8, SimpleForm 2.0.4, and Twitter Bootstrap 2.1.1 (via the bootstrap-sass gem 2.1.1.0).

The user should be able to add a contact from a modal popup window. If there are validation errors, they should appear inline, just as if the user were using a non-modal version of the form (red border around field, error message next to field).

I load the modal like this:

<a data-toggle="modal" data-target="#new-contact-modal">Go modal!</a>

Here is the Bootstrap modal, which calls the same contacts/contact_fields partial used in the non-modal version. app/views/contacts/_new_modal.html.erb:

<div id="new-contact-modal" class="modal hide fade" tabindex="-1" 
     role="dialog" aria-labelledby="new-contact-modal-label" 
     aria-hidden="true">
  <div class="modal-header">
    <button type="button" class="close" data-dismiss="modal" 
     aria-hidden="true">×</button>
    <h3 id="new-contact-modal-label"><%= t("contacts.new.header") %></h3>
  </div>
  <%= simple_form_for(@contact, 
      :remote => true,
      :html => {:class => "form-horizontal", 
                "data-type" => :json }) do |contact_form| %>
    <div id="new-contact-body" class="modal-body">
      <%= render 'contacts/contact_fields', :f => contact_form %>
    </div>
    <div class="modal-footer">
      <%= contact_form.submit :class => "btn btn-primary", 
          :"data-loading-text"=> ('simple_form.creating') %>
      <%= t('simple_form.buttons.or') %>
      <a data-dismiss="modal" aria-hidden="true">
        <%= t('simple_form.buttons.cancel') %>
      </a>
    </div>
  <% end %>
</div>

app/controllers/contacts_controller.rb (intentionally commented out the format.json line since I'm trying to send the whole modal back using JavaScript):

def create
  @contact = Contact.new(params[:contact])
  <...some additional processing...>
  respond_to do |format|
    if @contact.save
      format.html { flash[:success] = "Contact added."
                    redirect_to @contact }
      format.json { render json: @contact, status: :created, location: @contact}
    else
      format.html { render action: "new" }
      #format.json { render json: @contact.errors, status: :unprocessable_entity }
      format.js { render 'new_modal_error' }
    end

app/views/contacts/new_modal_error.js.erb

var modal = "<%= escape_javascript(render :partial => 'contacts/new_modal', :locals => { :contact => @contact.errors }) %>";
$("#new-contact-modal").html($(modal));

app/assets/javascripts/contacts.js Some JQuery to reset the form and close the modal on success.

$(function($) {
  $("#new_contact")
    .bind("ajax:success", function(event, data, status, xhr) {
      // http://simple.procoding.net/2008/11/22/how-to-reset-form-with-jquery :
      $(this).each(function(){
        this.reset();
      });       
      $("#new-contact-modal").modal("hide");
    })
});

The good news is, this works when the form has no errors: the contact is added and the modal is hidden. However if there are validation errors, I get the message "JSON.parse: unexpected character". This comes from jquery.js, line 515, which is the return statement in this snippet:

// Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
    return window.JSON.parse( data );
}

If I inspect data, I see that is is the content of my new_modal_error.js file, fully expanded with the form errors, and escaped for JavaScript. But it's not JSON.

What am I missing? How do I get the page to process new_modal_error.js as a JavaScript file, not a JSON variable? Or is there an easier way to handle this altogether?


回答1:


The main issue here was calling the form with data-type => :json. That means it will expect a JSON response, but I want it to pass back JavaScript. The solution is to set data-type => :script (or just leave it off and let Rails infer JavaScript):

:html => {:class => "form-horizontal", 
          "data-type" => :script }) do |contact_form| %>

Thanks to this article for explaining the various data-types, and clarifying that data-type refers to the response, not the submission of data:

Rails 3 Remote Links and Forms Part 2: Data-type (with jQuery)

"jQuery’s .ajax() method provides an optional parameter called dataType to specify the desired data-type of the response."

Another issue that I think @wanghq was pointing to is that JQuery's .html() method updates the innerHTML of an object. I wound up creating a partial containing only the form, calling the partial inside a <div id="new-contact-form-wrapper"> wrapper, then targeting the wrapper to replace the form:

var myForm = "<%= escape_javascript(render :partial => 'contacts/new_modal_form', :locals => { :contact => @contact.errors }) %>";
$("#new-contact-form-wrapper").html(myForm);

I am still working on getting variables passed, the form cleared on success, etc. Since I'm using a partial from the controller, I'll probably just go ahead and put all the JQuery (for both success and failure) in there so I won't need app/assets/javascripts/contacts.js.




回答2:


I don't understand why you need reset the form. I think it's not necessary.

$(function($) {
  $("#new_contact")
    .bind("ajax:success", function(event, data, status, xhr) {
      ...
    })
});

One thing you need to fix is below line in your new_model_error.js.erb, otherwise you will have duplicate divs with id="new-contact-modal".

old:
$("#new-contact-modal").html($(modal)); 
new:
$("#new-contact-modal").html($(modal).html());

Let me know if you still have problem.



来源:https://stackoverflow.com/questions/13408508/display-inline-errors-with-simple-form-in-a-bootstrap-ajax-modal

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!