在Bootstrap Ajax模式中使用simple_form显示内联错误

时间:2012-11-16 00:15:51

标签: jquery twitter-bootstrap ruby-on-rails-3.2 simple-form

我发现了类似的StackOverflow问题herehere,但仍无法解决此问题。

我正在使用Rails 3.2.8,SimpleForm 2.0.4和Twitter Bootstrap 2.1.1(通过bootstrap-sass gem 2.1.1.0)。

用户应该能够从模态弹出窗口添加联系人。如果存在验证错误,它们应该显示为内联,就像用户使用表单的非模态版本(字段周围的红色边框,字段旁边的错误消息)。

我像这样加载模态:

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

这是Bootstrap模式,它调用非模态版本中使用的相同contacts/contact_fields部分。 应用/视图/联系人/ _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 (故意注释掉format.json行,因为我正在尝试使用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

应用/视图/联系人/ 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 一些JQuery重置表单并在成功时关闭模式。

$(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");
    })
});

好消息是,当表单没有错误时,这种方法有效:添加联系人并隐藏模态。但是,如果验证错误,我会收到消息“JSON.parse:unexpected character”。这来自jquery.js,第515行,这是此代码段中的return语句:

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

如果我检查data,我发现这是我的new_modal_error.js文件的内容,完全展开了表单错误,并转义为JavaScript。但它不是JSON。

我错过了什么?如何让页面作为JavaScript文件而不是JSON变量处理new_modal_error.js?或者是否有更简单的方法来处理这个问题?

2 个答案:

答案 0 :(得分:2)

这里的主要问题是使用data-type => :json调用表单。这意味着它会期待JSON响应,但我希望它能够传回JavaScript。解决方案是设置data-type => :script(或者只是让它关闭并让Rails推断JavaScript):

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

感谢本文解释各种数据类型,并澄清数据类型是指响应,而不是提交数据:

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

“jQuery的.ajax()方法提供了一个名为dataType的可选参数,用于指定所需的响应数据类型。”

我认为@wanghq指出的另一个问题是JQuery的.html()方法更新了对象的 innerHTML 。我最后创建了一个仅包含表单的部分,在<div id="new-contact-form-wrapper">包装器中调用partial,然后以包装器为目标替换表单:

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

我仍然致力于传递变量,表单成功清除等等。由于我使用的是控制器的部分,我可能只需要继续并放置所有JQuery(成功和失败)在那里,所以我不需要 app / assets / javascripts / contacts.js

答案 1 :(得分:0)

我不明白为什么你需要重置表格。我认为没有必要。

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

您需要解决的一件事是 new_model_error.js.erb 下面的行,否则您将有重复的div id =“new-contact-modal”

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

如果您还有问题,请告诉我。