📝

Hotwireでformのsubmit時にローディングを表示する

2024/03/12に公開

問題

以下のようなフォームがある。
このフォームのsubmit中のみローディングを表示したい。

books/index.html.slim
= simple_form_for(@book, url: new_book_path, html: { data: { turbo_frame: :content } }) do |f|
    = f.input :title
    = f.input :price
    = f.button :submit

= turbo_frame_tag :content
    = render hogehoge

結論

formのsubmit開始時にはturbo:submit-startが、formのsubmit終了時にはturbo:submit-endがそれぞれ発火される。
これらをハンドリングし、loadingの表示と非表示を切り替えることで実装する。

loading-controller.js
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
    static targets = ['content', 'loading']

    displayLoading() {
        this.contentTarget.classList.remove('d-none');
        this.loadingTarget.classList.add('d-none');
    }

    displayContent() {
        this.contentTarget.classList.add('d-none');
        this.loadingTarget.classList.remove('d-none');
    }
}
books/index.html.slim
= simple_form_for(@book, url: new_book_path, html: { data: { turbo_frame: :content, controller: :loading, action: 'turbo:submit-start->loading#displayLoading turbo:submit-end->loading#displayContent' } }) do |f|
    = f.input :title
    = f.input :price
    = f.button :submit

.d-none data-loading-target='loading'
    p ローディング中

div data-loading-target='content'
    = turbo_frame_tag :content
        = render hogehoge

参考

https://turbo.hotwired.dev/reference/events

https://www.mikewilson.dev/posts/using-hotwire-with-rails-for-a-spa-like-experience/

Discussion