2022-02-15
Turbo stream responses with request.js
I’ve been tinkering with request.js and it’s quite magical. From the client, we can make make typical REST requests get, post, put, patch, destroy
. We can even deliver a turbo-stream response. By adding responseKind: "turbo-stream"
to the options config, you can receive some_action.turbo_stream.erb. When hooked with a stimulus controller, the implementation is easier than you would imagine.
<!-- pages/index.html.erb -->
<div class="flex flex-col" data-controller="activity">
<div>
What would you like to do?
<%= select_tag "activity",
options_for_select(@options),
{ include_blank: true,
data: { activity_target: "input",
url: what_to_do_path,
action: "change->activity#select" } } %>
</div>
<div>
<div data-activity-target="loading" class="hidden">Loading...</div>
<%= turbo_frame_tag "option" %>
</div>
</div>
In the stimulus controller I import get
from the request.js library. When a change event is triggered on the select tag, select()
makes a get request. Notice how I use new URLSearchParams
to append the param to the url. You can also return a Promise object with your request.
// javascript/controllers/activity_controller.js
import { Controller } from "@hotwired/stimulus"
import { get } from "@rails/request.js"
export default class extends Controller {
static targets = [ "loading", "input" ]
select(event) {
let url = this.inputTarget.dataset.url
let body = document.getElementById("option")
let params = new URLSearchParams()
params.append("option", this.inputTarget.value)
this.loadingTarget.classList.remove("hidden")
body.textContent = ""
const request = get(`${url}?${params}`, { responseKind: "turbo-stream" })
request.then((response) => {
this.loadingTarget.classList.add("hidden")
})
}
}
From the controller, in your respond_to specify the turbo_stream format.
# controllers/pages_controller.rb
def what_to_do
@result = params[:option]
sleep 0.5
respond_to do |format|
format.turbo_stream
end
end
And finally, deliver HTML over the wire with your turbo_stream ☺︎
# views/pages/what_to_do.turbo_stream.erb
<%= turbo_stream.replace "option" do %>
<%= turbo_frame_tag "option" do %>
<% unless @result.blank? %>
Then you should <%= @result.downcase %>!
<% end %>
<% end %>
<% end %>