Search code examples
ruby-on-railsruby-on-rails-7

How do I dynamically update an instance variable using forms?


I'm working on my first RoR 7.1.3.2 project and I've set up a simple form to take customer orders. I have an instance variable called @total and I want to be able to update this total to be equal to the sum of all number_fields, so that I get a total number of items ordered. I want this to update every time a number_field in the form is updated, that way customers can get an accurate count of items they are buying as they fill out the form.

I don't know much javascript but I was messing around with it but I'm honestly not sure how to access instance variables from javascript, I know I can update the text context of a div but I would really like to be able to be able to have an instance variable rather than just outputting some text, that way I can use that variable to interact with my database easier.

Another thing I thought of was to call some action in my OrdersController that updates the variable, but I'm not sure how this would work or if it would be the best way to do it.

I've been looking around at the documentation, I really have, but I guess I just might not know where to look since I couldn't find anything about it. Would appreciate any help. Here is my code:

<div class ="mt-2">
  <%= form_with model: @order do |form| %>
    <%= form.hidden_field "user", value: current_user.id %>
    <% @total = 0.00 %>   
    <% @items.each do |item| %>
      <%= form.fields_for OrderToItem.new, index: item.id do |item_form| %>
        <div><%= item_form.label :amount, item.name %></div>
        <div><%= item_form.number_field :amount, min: 0 %></div>
        <div><%= item_form.hidden_field :id, value: item.id %></div>
        <br>
      <% end %>
    <% end %> 

    <div><%= number_to_currency(@total, unit: "$", precision: 2) %></div>
    <%= form.submit "Submit Order", class: "bg-amber-950 rounded-xl p-2 mt-2 font-bold text-white" %>
  <% end %>
</div>

Solution

  • Add a event for amount field

    <div><%= item_form.number_field :amount, min: 0, onchange: "updateTotal()" %></div>
    

    Add id to element show total amount:

    <div id="total"><%= number_to_currency(@total, unit: "$", precision: 2) %></div>
    

    Add js code for update total amount when you have change on item cmount:

    <script>
      function updateTotal() {
        var total = 0;
        document.querySelectorAll('[name$="[amount]"]').forEach(function(input) {
          total += parseFloat(input.value) || 0;
        });
        document.getElementById('total').innerText = "$" + total.toFixed(2);
      }
    </script>

    This is pseudo code, you may have to edit it a bit and refactor