Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save john-hamnavoe/354875595c44ba4cfe1cd3276652e085 to your computer and use it in GitHub Desktop.
Save john-hamnavoe/354875595c44ba4cfe1cd3276652e085 to your computer and use it in GitHub Desktop.
Basic approach to having default value on field populated by selection on select box

Introduction

For example have form with select box which has list of reasons and when user selects the reason we want to populate an amount field on the form. The reason table has the amount as one of its columns. In this example we have adjusments and adjustment_reasons when user creates a new adjustment they pick reason it populates the amount with default value from the adjustment reason.

Stimulus Controller

We will create reason_controller.js in app/javascript/controllers.

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = [ "amountField" ]

  change(event) {
    let reason_id = event.target.selectedOptions[0].value
    let amountField = this.amountFieldTarget

    const fetchPromise = fetch(`/adjustment_reasons/${reason_id}.json`);

    fetchPromise.then((response) => {
      const jsonPromise = response.json();
      jsonPromise.then((data) => {
        amountField.value = data.amount
      });
    });
  }
}

The register it in app/javascript/controllers/index.js

import ReasonController from "./reason_controller"
application.register("reason", ReasonController)

Application Controller/Views to fetch Reason

We are using standard show method on the adjustments_reasons getting it to return JSON. It just uses before action callback before_action :set_adjustment_reason, only: %i[ show edit update destroy ] to get the reason.

Then use JSON partials app/views/adjustment_reasons/show.json.jbuilder:

json.partial! "adjustment_reasons/adjustment_reason", adjustment_reason: @adjustment_reason

And app/views/adjustment_reasons/_adjustment_reason.json.jbuilder:

json.extract! adjustment_reason, :id, :description, :amount, :adjustment_type_id, :created_at, :updated_at
json.url adjustment_reason_url(adjustment_reason, format: :json)

Form

Make sure both the select drop down and the target field in enclosed in div with data-controller="reason" (other fields and layout will be on form just showing the main changes). Using ViewComponents the main thing with select is to add the action to fire on change data: {action: "change->reason#change"} And the main the thing with the input field is to set target data: {"reason_target": "amountField"}

<div data-controller="reason">
  <%= render Forms::FieldComponent.new(form, :adjustment_reason_id, label: "Reason") do |field| %>
    <% field.with_input_select(options: adjustment_reasons_for_select(form.object.adjustment_reason_id), include_blank: true, required: true, data: {action: "change->reason#change"}) %>
  <% end %>
  <%= render Forms::FieldComponent.new(form, :amount) do |field| %>
    <% field.with_input_currency(data: {"reason_target": "amountField"}) %>
  <% end %>        
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment