Search code examples
javascriptruby-on-railsstimulusjs

RoR, Stimulus.js: A simple input calculation?


I am new to stimulus. I am trying to add up number/currency inputs and display in another field (the fields are decimal attributes) as the user types in their values but I can't get it to work.

Here I want to add 'land cost' + 'prof services' and display it in 'total cost' field.

My controller:

cost_calculate.controller.js

import { Controller } from 'stimulus'

export default class extends Controller {

  static targets = [ 'landCost', 'profServices', 'totalCost' ]

  updateTotalCost () {
    const totalCost = this.landCost() + this.profServices() 
    this.totalCostTarget.value = Number(totalCost).toFixed(2)
  }

  landCost () {
    return parseInt(this.landCostTarget)
  }

  profServices () {
    return parseInt(this.profServicesTarget)
  }

  totalCost () {
    return parseInt(this.totalCostTarget)
  }
}

My form:

<%= simple_form_for @project, html: { "data-controller" => "cost-calculate" }, url: wizard_path(step, project_id: @project.id) do |f| %> 
    
      
<%= f.text_field :land_cost, data: { target: 'cost-calculate.landCost', action: "change->cost-calculate#updateTotalCost" }, class: "project-dropdown-width" %>
    
<%= f.text_field :prof_services, data: { target: 'cost-calculate.profServices', action: "change->cost-calculate#updateTotalCost" }, class: "project-dropdown-width" %> 
    
<%= f.text_field :total_cost, data: { target: 'cost-calculate.totalCost' }, label: false, class: "project-dropdown-width" %>
                      
<% end %>

It keeps printing NaN in the 'totalCost' field. I'm not entirely confident my code is right in controller or view either for what I want to do.

For example, I want to achieve this but just adding two fields together

https://ngaunhien.net/blog/simple-input-calculation-with-stimulusjs

Would appreciate any guidance. ty.


Solution

  • You should use the value and parse and set the default value of 0 if no value exists.

    You should modify the controller as

    import { Controller } from 'stimulus'
    
    export default class extends Controller {
      
      static targets = [ 'landCost', 'profServices', 'totalCost' ]
      
      updateTotalCost () {
        const totalCost = this.landCost() + this.profServices()
        this.totalCostTarget.value = Number(totalCost).toFixed(2)
      }
    
      landCost () {
        return parseInt(this.landCostTarget.value || 0)
      }
    
      profServices () {
        return parseInt(this.profServicesTarget.value || 0)
      }
    
      totalCost () {
        return parseInt(this.totalCostTarget.value)
      }
    }