例えば Hotwire の Turbo Frame を使って検索機能を作る場合、検索結果に検索パラメータを付与した固有の URL にしたくなります。通常だと Turbo Frame の切り替え時には URL は変化しません。標準でサポートする Proposal も出ていますが微妙な部分なので将来的にサポートされるかは分かりません。
とりあえず、シンプルなコードでも似たようなことは実現できるのでコードを紹介します。
サンプルコードは Article 一覧の status
フィールドが 0
か 1
のものを検索し、結果を Turbo Frame で表示しています。URL は /aritlces?status=0
や /articles?status=1
を想定しています( JS が使えなくても検索できるようなインターフェイスに統一するのが良いと思います)。
Stimulus のコントローラでは検索用のフォームデータを取得し、QueryString に変換をします。それを Turbo が提供する navigator
オブジェクトを使って history.push
するだけです。
import { Controller } from 'stimulus';
import { navigator } from '@hotwired/turbo';
export default class extends Controller {
static targets = [ 'input', 'form' ];
search() {
const queryString = new URLSearchParams(new FormData(this.formTarget)).toString();
const url = location.origin + location.pathname + '?' + queryString;
this.formTarget.dispatchEvent(new CustomEvent('submit', { bubbles: true }));
navigator.history.push(new URL(url));
}
}
<%= form_with(url: articles_path, method: :get, data: { turbo_frame: 'articles', controller: 'article', article_target: 'form' }) do |form| %>
<%= form.radio_button :status, 0, data: { article_target: 'input', action: 'article#search' } %>
<%= form.radio_button :status, 1, data: { article_target: 'input', action: 'article#search' } %>
<% end %>
<%= turbo_frame_tag "articles" do %>
<% @articles.each do |article| %>
<%= article.title %>
<% end %>
<% end %>
シンプルですね。