I'm working with Hotwire the last month or two and trying to understand how to reload a specific turbo-frame after it renders the first time.
Let's say I have a simple rails controller for user searches. If it has a param of name
, return users matching that name
, if not, return all users.
class UserSearchController
def show
return User.where(name: params[:name]) if params[:name].present?
return User.all
end
end
I have a Turboframe hooked up that is correctly lazy loading all users in the DOM. What I'm trying to figure out is how I can update that Turboframe and redraw the frame. I've played around a bit with Stimulus and trying to set the src to the endpoint, that's the suggestions I've seen in other posts:
reload() {
const {src: src} = this;
this.src = null;
this.src = src;
}
That doesn't seem to work though, it doesn't redraw the turboframe. I can see it's making the request though to the rails backend.
Would anyone be able to point me in the direction of reloading/redrawing a frame after a page loads? I'm not sure if I'm completely off or am in the right ballpark.
You need some instance variables in that show
action or render locals: {..
, otherwise, you return into nothing. In stimulus controller, this
refers to controller instance, without seeing the rest of it, it looks like it does nothing.
Copy this to any page and click away to reload:
<%= turbo_frame_tag :reloadable, style: "display:none;" do %>
<%= request.uuid %>
<% end %>
# clicking this frame will load that ^ frame, because it's first.
<%= turbo_frame_tag :reloadable, src: request.url, onclick: "reload()" %>
Duplicate ids, I know. Put it on separate pages, not duplicate anymore.
Because onclick
isn't a cool thing to do:
// app/javascript/controllers/hello_controller.js
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
reload() {
this.element.reload();
// this works as well
// this.element.src = this.element.src;
// not sure if you would ever need to do it this way
// this.element.removeAttribute("complete");
}
}
<%= turbo_frame_tag(:reloadable, style: "display:none;") { request.uuid } %>
<%= turbo_frame_tag :reloadable, src: request.url,
data: {
controller: "hello",
action: "click->hello#reload"
}
%>
https://turbo.hotwired.dev/reference/frames#functions
As for the search form:
# app/views/any/where.html.erb
<%= form_with url: "/users", method: :get,
data: {turbo_frame: :users} do |f| %>
<%= f.search_field :name, placeholder: "search by name" %>
<%= f.button "Search" %>
<% end %>
# load this frame from `src`. load it again from the form submission response.
<%= turbo_frame_tag :users, src: "/users", target: :_top %>
# app/views/users/index.html.erb
<%
scope = User.all
scope = scope.where(name: params[:name]) if params[:name].present?
@users = scope
%>
<%= turbo_frame_tag :users, target: :_top do %>
<% @users.each do |user| %>
<%= user.name %>
<% end %>
<% end %>
https://turbo.hotwired.dev/handbook/frames#targeting-navigation-into-or-out-of-a-frame