(1) 在布局文件中将弹出层的代码和主体代码分开
</footer> <%= yield(:page_modal) if content_for?(:page_modal) %> <%= javascript_include_tag "application" %> <%= yield(:page_javascript) if content_for?(:page_javascript) %> </div> <!-- /container --> </body> </html>
(2)改写添加商品的时候按钮的方法,增加data属性,里面设定当按钮点击的时候,
打开哪一个model,在model的代码里,调用form这个局部模板,
在下面的js代码里声明这个model,并且声明这个model在加载的时候不显示。
app/views/products/index.html.erb
1 <%- model_class = Product -%> 2 <div class="page-header"> 3 <h1><%=t '.title', :default => model_class.model_name.human.pluralize.titleize %></h1> 4 </div> 5 <table class="table table-striped"> 6 <thead> 7 <tr> 8 <th><%= model_class.human_attribute_name(:id) %></th> 9 <th><%= model_class.human_attribute_name(:name) %></th> 10 <th><%= model_class.human_attribute_name(:price) %></th> 11 <th><%= model_class.human_attribute_name(:description) %></th> 12 <th><%= model_class.human_attribute_name(:created_at) %></th> 13 <th><%=t '.actions', :default => t("helpers.actions") %></th> 14 </tr> 15 </thead> 16 <tbody id="productsTable"> 17 <%= render @products %> 18 </tbody> 19 </table> 20 <%= link_to t('.new', :default => t("helpers.links.new")), 21 new_product_path, 22 :class => 'btn btn-primary', 23 data: {toggle: "modal", target: "#newProductFormModal"} %> 24 25 <%= content_for :page_modal do %> 26 <div class="modal fade" id="newProductFormModal" role="dialog" aria-labelledby="myModalLabel" 27 aira-hidden="true"> 28 <div class="modal-dialog"> 29 <%= form_for @product, remote: true, :html => {:class => 'form-horizontal', 30 id: "newProductForm"} do |f| %> 31 <div class = "modal-content"> 32 <div class="modal-header"> 33 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button> 34 <h4 class="modal-title">添加一个商品</h4> 35 </div> 36 37 <div class="modal-body"> 38 <%= render partial: "input", locals: {f: f} %> 39 </div> 40 41 <div class="modal-footer"> 42 <%= link_to t('.cancel', :default => t('helpers.links.cancel')), '#', 43 :class => 'btn btn-default', data: {dismiss: "modal"} %> 44 <%= f.submit nil, :class => 'btn btn-primary', :data => { :"disable-with" => "请稍等..."} %> 45 </div> 46 </div> 47 <% end %> 48 </div> 49 </div> 50 <div class="modal fade" id="editProductFormModal" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> 51 <div class="modal-dialog"> 52 <%= form_tag "", method: :put, remote: true, data: { type: "json" }, id: "editProductForm", class: "form" do %> 53 <div class="modal-content"> 54 <div class="modal-header"> 55 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> 56 <h4 class="modal-title">编辑一个商品</h4> 57 </div> 58 <div class="modal-body"> 59 <div class="alert alert-dismissible alert-danger" id="alert-content"> 60 <button type="button" class="close" data-dismiss="alert">×</button> 61 <div id="msg"></div> 62 </div> 63 <div class="form-group"> 64 <%= label_tag "product[name]", Product.human_attribute_name("name"), :class => 'control-label' %> 65 <%= text_field_tag "product[name]", "", :class => 'form-control', id: "editProductName" %> 66 </div> 67 <div class="form-group"> 68 <%= label_tag "product[description]", Product.human_attribute_name("description"), :class => 'control-label' %> 69 <%= text_field_tag "product[description]", "", :class => 'form-control', id: "editProductDescription" %> 70 </div> 71 <div class="form-group"> 72 <%= label_tag "product[price]", Product.human_attribute_name("price"), :class => 'control-label' %> 73 <%= text_field_tag "product[price]", "", :class => 'form-control', id: "editProductPrice" %> 74 </div> 75 </div> 76 <div class="modal-footer"> 77 <%= link_to t('.cancel', :default => t("helpers.links.cancel")), '#', :class => 'btn btn-default', data: {dismiss: "modal"} %> 78 <%= submit_tag t('.confirm', :default => t("helpers.links.confirm")), :class => 'btn btn-primary', :data => { :"disable-with" => "请稍等.. 79 </div> 80 </div> 81 <% end %> 82 </div> 83 </div> 84 85 <% end %> 86 87 <%= content_for :page_javascript do %> 88 <script> 89 $('#newProductFormModal').modal({ 90 show: false, 91 }) 92 $('#editProductFormModal').modal({ 93 show: false, 94 }) 95 </script> 96 <% end %>
(3) 点击新建我们可以看到弹出层的效果已经实现了,但是form里又包含了相同的功能的按钮,
这个时候我们需要对form再进行一个拆解,将它的控件部分提供给弹出层。
新建模板app/views/products/_input.html.erb
<div class="control-group"> <%= f.label :name, :class => 'control-label' %> <div class="controls"> <%= f.text_field :name, :class => 'form-control' %> </div> <%= error_span(@product[:name]) %> </div> <div class="control-group"> <%= f.label :price, :class => 'control-label' %> <div class="controls"> <%= f.text_field :price, :class => 'form-control' %> </div> <%= error_span(@product[:price]) %> </div> <div class="control-group"> <%= f.label :description, :class => 'control-label' %> <div class="controls"> <%= f.text_field :description, :class => 'form-control' %> </div> <%= error_span(@product[:description]) %> </div>
在form里引用这个模板app/views/products/_form.html.erb
<%= form_for @product, :html => { :class => "form-horizontal product" } do |f| %> <% if @product.errors.any? %> <div id="error_expl" class="panel panel-danger"> <div class="panel-heading"> <h3 class="panel-title"><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h3> </div> <div class="panel-body"> <ul> <% @product.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> </div> <% end %> <%= render partial: "input", locals: {f: f} %> <%= f.submit nil, :class => 'btn btn-primary', :data => { :"disable-with" => "请稍等..." } %> <%= link_to t('.cancel', :default => t("helpers.links.cancel")), products_path, :class => 'btn btn-default' %> <% end %>
(4)刷新页面,再次点击新建按钮,弹出层效果已经实现了,在弹出层新建一个商品,可以看到页面没有关闭,
页面上也没有显示新添加的商品,进到log里可以看到,刚才我们提交的是一个post操作,产生的是js响应,
在完成之后,它返回的也是一个js响应。在脚手架为我们创建代码的时候,里面并没有添加如何执行js的响应,
我们需要手动添加一个,比如在create方法里,进入respond_to,
def create @product = Product.new(product_params) respond_to do |format| if @product.save format.html { redirect_to @product, notice: 'Product was successfully created.' } format.json { render :show, status: :created, location: @product } else format.html { render :new } format.json { render json: @product.errors, status: :unprocessable_entity } end format.js end end
def update respond_to do |format| if @product.update(product_params) format.html { redirect_to @product, notice: 'Product was successfully updated.' } format.json else format.html { render :edit } format.json { render json: @product.errors.full_message.join(', '), status: :error} end format.js end end def destroy @product.destroy respond_to do |format| format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' } format.json { head :no_content } format.js end end def edit respond_to do |format| format.html format.json {render json: @product, status: :ok, location: @product } end end
创建新文件app/views/products/create.js.erb ,这样做的好处是,我们可以在js文件里使用erb语法,
在文件中先判断商品是否保存成功,如果保存失败,需要演示它的错误信息,
如果保存成功,需要先将商品添加到列表里,然后关闭这个弹出层,最后将这个弹出层里的表单重置一下,
否则再次点击添加按钮的时候,刚才添加的文字还在弹出层表单里
<% if @product.errors.any? %> $('#newProductInput').prepend('<%= j render "errors" %>'); <% else %> $('#productsTable').prepend('<%= j render(@product) %>') $('#newProductFormModal').modal('hide'); $('#newProductForm')[0].reset(); <% end %>
需要注意一下上面使用了j 这个辅助方法,它会将我们产生的信息转移成js方法