Trigger Rails 7 form from JS (from Stimulus)

Edit
equivalent
Public
Rails
stimulus
hotwire
importmaps
JavaScript

Best approach - just click the button with Stimulus 🙂


Seriously, you will save so much hustle with JS. Just hide the submit button an tell JS to click it.

// app/javascript/controllers/foo_controller.js
import { Controller } from "@hotwired/stimulus"

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

  save(event) {
    this.btnTarget.click
  }
}

<form method="post" url="/whatever"> 
  <div class="w-5 h-5 bg-red" data-action="click->foo#save">

  <input type="submit" class="hidden" data-foo-target="btn"> 
</form>


--------------------------------

hands down above ☝️ is the best approach -  if this goes in hand wit Rails SSR convention + sprinkles of JS. It solves 99.9% cases. If you are really stubborn and think JS does better job here are few more approaches:



Request.js


@rails/request.js encapsulates the logic to send by default some headers that are required by rails applications like the X-CSRF-Token.

GET example


import {Controller} from "@hotwired/stimulus"
import {put} from "@rails/request.js"
//...
change(event) {
  let params = new URLSearchParams()

  params.append(this.paramValue, event.target.selectedOptions[0].value)

  get(`${this.urlValue}?${params}`, { responseKind: "turbo-stream" })
}


PUT example

# a/js/controllers/ts/select-update.js
import {Controller} from "@hotwired/stimulus"
import {put} from "@rails/request.js"

export default class extends Controller {
  static values = {
    url: String,
  }

  update(event) {
    put(this.urlValue, {
      body: JSON.stringify({ block: { [event.target.id] : event.target.value}}),
      responseKind: "turbo-stream"
    });
  }
}


<div class="flex"
    data-controller="ts--select-update"
    data-ts--select-update-url-value="<%= something_important_url %>">
  <%= f.input :provider,
        as: :select,
        collection: [...],
        label: false,
        input_html: {
          data: {controller: "ts--select", action: "ts--select-update#update"},
          id: :provider
        } %>

The url points to controller that will do a hotwire update of a content (so the update Stimulus method don't really do anything with response, stream updates content)
<%= turbo_stream.replace "modal" do %>
  whatever
<% end %>





Use Rails UJS


setup

$ ./bin/importmap pin @rails/ujs

this will add this  line to importmaps:
pin "@rails/ujs", to: "https://ga.jspm.io/npm:@rails/[email protected]/lib/assets/compiled/rails-ujs.js"

Now include @rails/ujs to your javascript. In file javascript/controllers/application.js add:
import Rails from '@rails/ujs';

Rails.start();

Now you will be able to call 

submitForm = (e) => {   
  Rails.fire(this.element, 'submit');
}