I have a form I want to submit automatically whenever any input field is changed. I am using Turbo Streams, and if I use onchange: "this.form.submit()"
it isn't captured by Turbo Streams and Rails uses a standard HTML response. It works fine when clicking the submit button. How can I work around this?
There is a discussion on the hotwire forum, where Mark Godwin figured out why form.submit()
isn't working with turbo:
Turbo intercepts form submission events, but weirdly, the JS formElement.submit() method does not trigger the submit event.
And Jacob Daddario figures out that you can use form.requestSubmit()
instead:
It turns out that the turbo-stream mechanism listens for form submission events, and for some reason the submit() function does not emit a form submission event. That means that it’ll bring back a normal HTML response. That said, it looks like there’s another method, requestSubmit() which does issue a submit event.
So you can change your code slightly, and use requestSubmit()
if a browser supports it, and use
submit()
if not:
onchange: "this.form.requestSubmit ? this.form.requestSubmit() : this.form.submit()"
Update:
As BenKoshy pointed out, in Turbo 7.1.0, a polyfill was added so you can use form.requestSubmit()
without checking for browser support, so you can add this to your input field:
onchange: "this.form.requestSubmit()"
I need to implement this for an app with lots of forms. I wound up using Stimulus. Below is the whole controller:
import { Controller } from "stimulus"
const _ = require("lodash")
export default class extends Controller {
connect() {
let that = this;
that.element.addEventListener('change', _.debounce(that.handleChange, 500))
}
handleChange(event) {
event.preventDefault()
// event.target.name // => "user[answer]"
// event.target.value // => <user input string>
event.target.form.requestSubmit()
}
}
and here it's used in a form with a single text input. NOTE the controller is attached to the form, not to the inputs.
<%= turbo_frame_tag dom_id(form_model) do %>
<%= form_with model: form_model,
format: :turbo_stream,
html: { data: { controller: "buttonless-form" } } do |f| %>
<%= f.hidden_field :question_id, value: question.id %>
<%= f.text_field :answer_value, class: "input shadow wide", placeholder: "Enter your answer here" %>
<% end %>
<div id=<%= "question_#{question.id}_output" %>>
<p> <!-- feedback to the user shows up here via Turbo -->
</div>
<% end %> <!-- end turbo frame -->
© 2022 - 2024 — McMap. All rights reserved.