Use <turbo-frame> with list of items (<ul> <li>)

Hi :slight_smile:,

Is it possible to use <turbo-frame> with <ul> <li>.

I followed this tutorial: https://github.com/thoughtbot/hotwire-example-template/tree/hotwire-example-pagination.

With <div>, I have no problem.

With <ul> <li>, I don’t see how I could do it.

My code is :

// app/views/messages/index.html.erb
<h1>Messages</h1>

<turbo-frame id="messages_page_<%= @page.page %>" class="grid gap-2" target="_top">
  <ul>
	  <% if @page.prev %>
		<turbo-frame id="messages_page_<%= @page.prev %>" class="group" data-turbo-action="replace"
					 data-controller="element" data-action="turbo:frame-render->element#replaceWithChildren">
		  <%= link_to pagy_url_for(@page, @page.prev), rel: "prev", class: "hidden group-first-of-type:block" do %>
			Previous page
		  <% end %>
		</turbo-frame>
	  <% end %>

	  <% @messages.each do |message| %>
		<li class="border border-solid">
		  <%= message.content %>

		  <p>
			Posted by: <%= link_to message.author, messages_path(author: message.author) %>
		  </p>
		</li>
	  <% end %>

	  <% if @page.next %>
		<turbo-frame id="messages_page_<%= @page.next %>" class="group" data-turbo-action="replace"
					 src="<%= pagy_url_for(@page, @page.next) %>" loading="lazy"
					 data-controller="element" data-action="turbo:frame-render->element#replaceWithChildren">
		  <%= link_to pagy_url_for(@page, @page.next), rel: "next", class: "hidden group-last-of-type:block" do %>
			Next page
		  <% end %>
		</turbo-frame>
	  <% end %>
  </ul>
</turbo-frame>

When wanting to wrap turbo-frames around elements that should only be wrapped by a certain element (e.g. a <li> should be inside a <ul> or <ol>, a <tr> should be inside a <tbody>, <thead>, <tfoot> or <table>, etc…) then it’s tricky.

The best thing you can do in those cases is to have this hidden turbo-frame that returns hidden <turbo-stream action="replace" target="dom_id"> tags.

Let’s imagine in your case that:

  • your Previous link has id messages_previous_link,
  • your Next link as id messages_next_link and
  • your <ul> has id messages
  • your hidden <turbo-frame> (which would only ever contain <turbo-stream action="replace"> tags) has id pagination_frame

Your Previous link and your Next link would have data-turbo-frame="pagination_frame", indicating that a click on these should trigger an update to the pagination turbo-frame containing <turbo-stream>.

In that pagination_frame, there should be three <turbo-stream> tags:

<turbo-stream action="replace" target="#messages">
  <template>
    <!-- the new list of <li> -->
  </template>
</turbo-stream>

<turbo-stream action="replace" target="#messages_previous_link">
  <template>
    <!-- the link_to -->
  </template>
</turbo-stream>

<turbo-stream action="replace" target="#messages_next_link">
  <template>
    <!-- the link_to -->
  </template>
</turbo-stream>

You’ll see that I’m assuming here that your previous and next links will be outside your <ul> with id #messages, because I have separate <turbo-stream action="replace"> for each.

Also, the hidden #pagination_frame <turbo-frame> should be outside the <ul> with id #messages.

See the trick?

Thank you for your solution but there may be a simpler one.

1 Like