I have a table with infinite scroll working perfectly without reloading entire page. I'm now having issues with adding filter. Thanks to Phil Reynolds' article https://purpleriver.dev/posts/2022/hotwire-handbook-part-2 I was able to implement infinite load.
controller action
def index
if params[:query].present?
search = "%#{params[:query]}%"
alerts = Alert.where( "title ILIKE ?", search )
else
alerts = Alert.all
end
@pagy, @alerts = pagy(alerts, items: 100)
end
the table
<%= turbo_frame_tag "page_handler" %>
<table class="w-full border border-t-gray-300 table-auto">
<thead>
<tr class="bg-gray-200 text-gray-600 uppercase text-sm leading-3">
<th class="py-3 px-4 text-left">Severity</th>
<th class="py-3 px-3 text-left">Title</th>
...
</tr>
</thead>
<tbody id="alerts" class="text-gray-600 text-sm font-light">
<%= render "alerts_table", alerts: @alerts %>
</tbody>
</table>
<%= render "shared/index_pager", pagy: @pagy %>
alerts_pager partial
<div id="<%= controller_name %>_pager" class="min-w-full my-8 flex justify-center">
<% if pagy.next %>
<%= link_to 'Loading',
"#{controller_name}?query=#{params[:query]}&page=#{pagy.next}",
data: {
turbo_frame: 'page_handler',
controller: 'autoclick'
},
class: 'rounded py-3 px-5 bg-gray-600 text-white block hover:bg-gray-800'%>
<% end %>
</div>
turbo frame response
<%= turbo_frame_tag "page_handler" do %>
<%= turbo_stream_action_tag(
"append",
target: "alerts",
template: %(#{render "alerts_table", alerts: @alerts})
) %>
<%= turbo_stream_action_tag(
"replace",
target: "alerts_pager",
template: %(#{render "shared/index_pager", pagy: @pagy})
) %>
<% end %>
autoclick controller
import { Controller } from "@hotwired/stimulus"
import { useIntersection } from 'stimulus-use'
export default class extends Controller {
options = {
threshold: 0.5
}
connect() {
useIntersection(this, this.options)
}
appear(entry) {
this.element.click()
}
}
I also managed to make it working together with filter but it reloads full page.
<div id="<%= controller_name %>_filter" class="bg-gray-200 p-1 shadow-lg">
<div class="p-1 lg:w-1/3">
<%= form_with url: alerts_path, method: :get do %>
<%= text_field_tag "query",
nil,
placeholder: "Filter",
class: "inline-block rounded-md border border-gray-200 outline-none px-3 py-2 w-full" %>
<% end %>
</div>
</div>
I want to update content in the same turbo frame. But the problem is that turbo_stream_action_tag in the page_handler frame appends data. Do need to have another turbo_frame_tag that serves filter? How to implement it?
I tried to add <%= turbo_frame_tag "filter_handler" %>
to the index page and added sections below to turbo frame response
<%= turbo_frame_tag "filter_handler" do %>
<%= turbo_stream_action_tag(
"replace",
target: "alerts",
template: %(#{render "alerts_table", alerts: @alerts})
) %>
<% end %>
and added data: {turbo_frame: "filter_handler"}
attr to the filter. But it works incorrectly