简体   繁体   中英

Rails 4 jQuery / Ajax to refresh and add item to partial after create

I have a form with 2 nested forms. I am trying to refresh the second nested form once the first form is used to create an object which is what is inserted into the second form.

My ajax is working to be able to create and save my order_item which is created by my first f.fields_for :order_item but I am lost on how to then get my partial to refresh which is located in another controller.

Here is my parent form

<div class-"col-md-12">
<%= bootstrap_form_for(@quote) do |f| %>
<% if @quote.errors.any? %>
<div id="error_explanation">
    <h2><%= pluralize(@quote.errors.count, "error") %> prohibited this quote from being saved:</h2>

    <ul>
        <% @quote.errors.full_messages.each do |message| %>
        <li><%= message %></li>
        <% end %>
    </ul>
</div>
<% end %>
<%= f.hidden_field :quote_num, value:@current_user.company.starting_quote %>
<fieldset>
    <div class-"col-md-12">
        <div class="col-md-8">
            <%= f.collection_select :client_id, Client.order(:business_name), :id, :business_name, include_blank: true %>
        </div>
        <div class="col-md-4">
            <%= f.date_select :quote_exp, :order => [:month, :day, :year] %>
        </div>
        <div class="margin-bottom-10"></div>
        <div class="col-md-6">
            <%= f.grouped_collection_select :billing_address, Client.order(:business_name), :addresses, :business_name, :full_address, :full_address, include_blank: true %>
        </div>
        <div class="col-md-6">
            <%= f.grouped_collection_select :shipping_address, Client.order(:business_name), :addresses, :business_name, :full_address, :full_address, include_blank: true %>
        </div>
    </div>
</fieldset>
<div class="margin-bottom-10"></div>
<hr />
<div class="margin-bottom-10"></div>

<!-- Render Select Options for New Item -->
<div class="col-md-12">
    <%= f.fields_for :order_item do |ff| %>
    <div class="col-md-4">
        <%= ff.hidden_field :quote_id, value: @quote.id %>
        <%= ff.collection_select :category_id, Category.order(:name), :id, :name, include_blank: "Select Category", hide_label: true %>
    </div>
    <div class="col-md-6">
        <%= ff.grouped_collection_select :product_id, Category.order(:name), :products, :name, :id, :name, include_blank: true, hide_label: true %>
    </div>
    <div class="col-md-2">
        <%= ff.submit "Add Item", class:"btn-u btn-u-blue pull-right", id:"add_item" %>
    </div>
    <% end %>
</div>

<div class="margin-bottom-10"></div>
<hr />
<div class="margin-bottom-10"></div>
<div class="table-search-v1 margin-bottom-20">
    <div class="table-responsive">
        <table class="table table-hover table-bordered table-striped table-condensed">
            <thead>
                <th style="width: 20px;"></th>
                <th style="width: 300px;">Product</th>
                <th>Price</th>
                <th style="width: 20px;">Quantity</th>
                <th>Discounts</th>
                <th>Total</th>
            </thead>
            <tbody id="list">
                <!-- this is where we display the results -->
                <%= f.fields_for :order_items do |builder| %>
                    <%= render 'order_item_fields', f: builder, show_total: true %>
                <% end %>

            </tbody>
        </table>

    </div>
</div>
</div>
<div class="margin-bottom-10"></div>
<hr />
<div class="margin-bottom-10"></div>
<fieldset>

    <div class="col-md-12">
        <div class="col-md-6">
            <%= f.text_area :special_note, rows:7, label:"Special Notes" %>
        </div>
        <div class="col-md-6">
            <div id="total_deposit">
            </div>
            <div class="col-md-4">
                <h5>Sales Tax</h5>
            </div>
            <div class="col-md-8">
                <%= f.text_field :tax_amount, hide_label: true %>
            </div>
            <div class="col-md-4">
                <h5>Sub-Total</h5>
            </div>
            <div class="col-md-8">
                <%= f.text_field :sub_total, hide_label: true %>
            </div>
            <div class="col-md-4">
                <h5>Shipping</h5>
            </div>
            <div class="col-md-8">
                <%= f.text_field :shipping_cost, hide_label: true %>
            </div>
            <div class="col-md-4">
                <h5>Total</h5>
            </div>
            <div class="col-md-8">
                <%= f.text_field :total, hide_label: true %>
            </div>
        </div>
    </div>
</fieldset>
<div class="margin-bottom-10"></div>
<hr />
<div class="margin-bottom-10"></div>
<div class="tag-box tag-box-v1 box-shadow shadow-effect-1 col-md-12">
    <h4>Deposit</h4>
    <%= f.check_box :deposit, label: "Require Deposit" %>
    <%= f.text_field :deposit_amount, hide_label: true, placeholder:"Enter Amount" %>
</div>
<div class="margin-bottom-10"></div>
<div class="tag-box tag-box-v1 box-shadow shadow-effect-1 col-md-12">
    <h4>Shipping Information</h4>
    <div class="col-md-6">
        <select class="form-control" id="shipping">
            <option value="0" selected="selected">Not Applicable</option>
            <option>Overnight Shipping</option>
            <option>2 Day Shipping</option>
            <option>3 Day Shipping</option>
            <option>Ground (5-7 days)</option>
        </select>
    </div>
    <div class="col-md-6">
        <%= f.text_field :shipping_cost, hide_label: true, placeholder:"Enter Amount" %>
    </div>
</div>
<div class="actions">
    <%= f.submit "Save Quote", class:"btn-u pull-right" %>
</div>
<% end %>
</div>
<script>
$("#quote_deposit").change(function(){
    $("#quote_deposit_amount").toggle($(this).is(':checked'));
});

$('#quote_deposit').trigger('change');

var product = $("#quote_product_id").val()

</script>

Here is my nested form which is displayed by row in my table in my main form. This is the partial that should be refreshed after create to show all items now associated with the quote. If possible, I would like to only add the element and using js so as to not refresh the entire partial.

<fieldset>
<tr>
    <td>
        <div class="btn-group">
            <button type="button" class="btn-u dropdown-toggle" data-toggle="dropdown">
                <i class="fa fa-angle-down"></i>
            </button>
            <ul class="dropdown-menu" role="menu">
                <li><%= f.hidden_field :_destroy %>
                <%= link_to "Remove Item", '#', class: "remove_fields btn btn-link" %></li>
                <li><button class="btn btn-link">Add Custom Item</button></li>
                <li><button class="btn btn-link">Remove Item</button></li>
            </ul>
        </div>
    </td>
    <td>
        <h5><%= f.object.product.name %></h5>
    </td>
    <td>
        <h5 class="text-right"><span style="color: green"> <%= number_to_currency f.object.unit_price %></span></h5>
    </td>
    <td>
        <%= f.number_field :quantity, min: 1, hide_label: true %>
        <%= f.hidden_field :_destroy %>
    </td>
    <td>
        <%= f.text_field :discount, hide_label: true %>
    </td>
    <td>
        <h5 class="text-right"><span style="color: green"><%= number_to_currency f.object.total_price %></span></h5>
    </td>
</tr>
</fieldset>

My jquery ajax call to create object

$('form').on 'click', '#add_item', (e) ->
e.preventDefault()
product = $('#quote_order_item_product_id :selected').val()
quote = $('#quote_order_item_quote_id').val()
console.log(product)
console.log(quote)
$.ajax '/order_items',
  type: 'POST'
  dataType: 'json'
  data: { order_item: { product_id: product, quote_id: quote } }
  success:(data) ->
    alert data.id
  error: (jqXHR, textStatus, errorThrown) ->
    alert textStatus

And my order items create method

def create
@order_item = OrderItem.new(order_item_params)
 respond_to do |format|
   if @order_item.save
     format.js do
        render 'quotes/' + @quote.id + '/refresh'
     end
   else
     format.json { render json: @order_item.errors, status: :unprocessable_entity }
   end
  end
 end

After creating the proper route from quote:id/order_item I then edited my controller to only return js (or json, does not matter) on success. I then changed my jquery coffeescript method to look like this.

$('form').on 'click', '#add_item', (e) ->
e.preventDefault()
product = $('#quote_order_item_product_id :selected').val()
product_name = $('#quote_order_item_product_id :selected').text()
console.log(product_name)
count = $('.order-item').length
console.log(count)
quote = $('#quote_order_item_quote_id').val()
console.log(product)
console.log(quote)
$.ajax '/order_items',
  type: 'POST'
  dataType: 'json'
  data: { order_item: { product_id: product, quote_id: quote } }
  success:(data) ->
    id = data.id.toString()
    $root = $('.order-item:last').clone()

    $root.find(".remove_fields").attr('name',"quote[order_items_attributes][#{count}][_destroy]" )
    $root.find(".remove_fields").attr('id',"quote_order_items_attributes_#{count}__destroy]" )
    $root.find(".product").text(product_name)
    $root.find(".product-id").attr('value', product)
    $root.find(".price").text(data.unit_price)
    $root.find(".quantity_input").val("1")
    $root.find(".discount_input").val("")
    $root.find(".quantity_input").attr('name',"quote[order_items_attributes][#{count}][quantity]" )
    $root.find(".quantity_input").attr('id',"quote_order_items_attributes_#{count}_quantity]" )
    $root.find(".discount_input").attr('name',"quote[order_items_attributes][#{count}][discount]" )
    $root.find(".discount_input").attr('id',"quote_order_items_attributes_#{count}_discount]" )

    $root.appendTo('#list')

  error: (jqXHR, textStatus, errorThrown) ->
    alert textStatus

Essentially, what I am doing is on success, I get my object back as (data) and then I clone the previous table row and rebuild my form on the client side with all of the proper input values. You can build it through javascript I'm sure but my form is pretty complex and quite long so believe it or not, this was the short route.

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