如何使用Turbo Streams在输入更改时提交表单?

23

我有一个表单,我希望每当任何输入字段更改时自动提交。我正在使用Turbo Streams,如果我使用onchange:"this.form.submit()",它不会被Turbo Streams捕获,Rails会使用标准的HTML响应。点击提交按钮时可以正常工作。我该如何解决这个问题?

2个回答

58

在 hotwire 论坛上有一篇讨论,Mark Godwin 发现了为什么form.submit()与 Turbo 不兼容:

Turbo 拦截表单提交事件,但奇怪的是,JS 的 formElement.submit() 方法不会触发提交事件。

Jacob Daddario发现你可以使用 form.requestSubmit() 代替:

原来 Turbo-Stream 机制监听表单提交事件,但由于某些原因,submit() 函数不会触发表单提交事件。这意味着它将返回普通的 HTML 响应。不过,看起来还有另一种方法 requestSubmit() 可以发出表单提交事件。

所以你可以稍微更改你的代码,并使用 requestSubmit(),如果浏览器支持,否则使用submit():

onchange: "this.form.requestSubmit ? this.form.requestSubmit() : this.form.submit()"


更新:

正如BenKoshy所指出的,Turbo 7.1.0 中添加了一个polyfill,以便您可以使用form.requestSubmit()而不需要检查浏览器支持性,因此您可以将其添加到输入字段中:

onchange: "this.form.requestSubmit()"

7
我确认这有效。 - sparkle
2
有一个 polyfill 可以处理浏览器兼容性问题,只要安装最新版本的 turbo,就没问题了。 - BenKoshy
如果你使用的是form_with( ... method: :post ),那么这个方法可以正常工作。但是如果你使用的是form_with( ... method: :get ),那么表单将以HTML格式提交。为了修复这个问题,你可以使用form_with(... data: { turbo_stream: true })。这适用于最新版本的turbo-rails 1.4.0。 - Volodymyr
form.submit()不触发事件并没有什么奇怪的地方。一个标准的模式是监听"submit"事件,执行一些操作,然后在事件处理程序内部提交表单。虽然有可能进行缓解,但标准功能将导致无限循环。 - Michael Chaney

3

我需要为一个包含大量表单的应用程序实现这个功能。最终我采用了 Stimulus 实现。以下是整个控制器的代码:

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()
  }
}

这里它被用在一个只有一个文本输入框的表单中。注意控制器附加到了表单上而不是输入框上。

<%= 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 -->

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接