Trigger Rails 7 form from JS (from Stimulus)
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');
}import { Controller } from "@hotwired/stimulus"
import Rails from "@rails/ujs"
export default class extends Controller {
static values = {
url: String,
}
refresh(event) {
Rails.ajax({
url: this.urlValue,
type: "POST",
success: () => {
// .....
},
error: () => {
// ...
}
})
end
end