1. 程式人生 > >通過彈出層實現新建功能 ruby on rails

通過彈出層實現新建功能 ruby on rails

(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
<%- model_class = Product -%>
<div class="page-header">
  <h1><%=t '.title', :default => model_class.model_name.human.pluralize.titleize %></h1>
</div>
<table class="table table-striped">
  <thead>
    <tr>
      <th><%= model_class.human_attribute_name(:id) %></th>
      <th><%= model_class.human_attribute_name(:name) %></th>
      <th><%= model_class.human_attribute_name(:price) %></th>
      <th><%= model_class.human_attribute_name(:description) %></th>
      <th><%= model_class.human_attribute_name(:created_at) %></th>
      <th><%=t '.actions', :default => t("helpers.actions") %></th>
    </tr>
  </thead>
  <tbody id="productsTable">
    <%= render @products %>
  </tbody>
</table>
<%= link_to t('.new', :default => t("helpers.links.new")),
            new_product_path,
            :class => 'btn btn-primary',
            data: {toggle: "modal", target: "#newProductFormModal"} %>

<%= content_for :page_modal do %>
  <div class="modal fade" id="newProductFormModal" role="dialog" aria-labelledby="myModalLabel"
    aira-hidden="true">
    <div class="modal-dialog">
      <%= form_for @product, remote: true, :html => {:class => 'form-horizontal',
        id: "newProductForm"} do |f| %>
        <div class = "modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">x</button>
            <h4 class="modal-title">新增一個商品</h4>
          </div>

          <div class="modal-body">
            <%= render partial: "input", locals: {f: f} %>
          </div>

          <div class="modal-footer">
            <%= link_to t('.cancel', :default => t('helpers.links.cancel')), '#',
              :class => 'btn btn-default', data: {dismiss: "modal"} %>
              <%= f.submit nil, :class => 'btn btn-primary', :data => { :"disable-with" => "請稍等..."} %>
          </div>
        </div>
      <% end %>
    </div>
  </div>
 <div class="modal fade" id="editProductFormModal" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <%= form_tag "", method: :put, remote: true, data: { type: "json" }, id: "editProductForm", class: "form" do %>
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
            <h4 class="modal-title">編輯一個商品</h4>
          </div>
          <div class="modal-body">
            <div class="alert alert-dismissible alert-danger" id="alert-content">
              <button type="button" class="close" data-dismiss="alert">×</button>
              <div id="msg"></div>
            </div>
            <div class="form-group">
              <%= label_tag "product[name]", Product.human_attribute_name("name"), :class => 'control-label' %>
              <%= text_field_tag "product[name]", "", :class => 'form-control', id: "editProductName" %>
            </div>
            <div class="form-group">
              <%= label_tag "product[description]", Product.human_attribute_name("description"), :class => 'control-label' %>
              <%= text_field_tag "product[description]", "", :class => 'form-control', id: "editProductDescription" %>
            </div>
            <div class="form-group">
              <%= label_tag "product[price]", Product.human_attribute_name("price"), :class => 'control-label' %>
              <%= text_field_tag "product[price]", "", :class => 'form-control', id: "editProductPrice" %>
            </div>
          </div>
          <div class="modal-footer">
            <%= link_to t('.cancel', :default => t("helpers.links.cancel")), '#', :class => 'btn btn-default', data: {dismiss: "modal"} %>
            <%= submit_tag t('.confirm', :default => t("helpers.links.confirm")), :class => 'btn btn-primary', :data => { :"disable-with" => "請稍等..
          </div>
        </div>
      <% end %>
    </div>
  </div>

<% end %>

<%= content_for :page_javascript do %>
  <script>
    $('#newProductFormModal').modal({
      show: false,
    })
    $('#editProductFormModal').modal({
      show: false,
    })
  </script>
<% 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 edit
    respond_to do |format|
      format.html
      format.json {render json: @product, status: :ok, location: @product }
    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

建立新檔案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方法