1

In a view that displays a list of categories, there is a little part underneath that shows the "default" of these categories. When a user clicks there, it is replaced by a drop down form where they can select the new default. Upon submitting of the form, the two parts of the page - list of categories as well as lower part where the default is shown - shall be updated via turbo stream.

This works once. If I try to click the lower element for the second time, the whole page renders blank even though the network tab of the browser shows that something is arriving. I don't understand why that happens.

view (index page):

<%= turbo_frame_tag 'settings-content' do %>
  <h3 class="heading4">Available book formats</h3>
  <ul class="simple-list width-33" id="book-formats">
    <%= render 'new_form_entry' %>
    <%= turbo_frame_tag 'format-list' do %>
      <%= render @book_formats %>
    <% end %>
  </ul>
  <h3 class="heading4 margin-top-1 margin-bottom-50">Default Book Format</h3>
  <ul class="simple-list width-25">
    <li>
      <%= turbo_frame_tag 'default-format' do %>
        <%= render 'book_formats/set_default_form' %>
      <% end %>
    </li>
  </ul>
<% end %>

controller (relevant two methods):

  def set_default
    @book_formats = BookFormat.all.order(:name)
  end

  def update_default
    @new_default = BookFormat.find_by(name: book_format_params[:name])
    @default_book_format.update(fallback: false)
    @new_default.update(fallback: true)
    @default_book_format = @new_default
    @book_formats = BookFormat.all.order(:name)
  end

update_default.turbo_stream.erb

<%= turbo_stream.replace 'format-list' do %>
      <%= render @book_formats %>
<% end %>
<%= turbo_stream.replace 'default-format' do %>
      <%= render 'book_formats/set_default_form' %>
<% end %>

I am sure I am missing a small piece somewhere?

tkhobbes
  • 368
  • 3
  • 16

1 Answers1

3

turbo_frame_tag helper renders a <turbo-frame> tag and the form:

<turbo-frame id="default-format">
  <form>
    <!-- ... -->
  </form>
</turbo-frame>

turbo_stream.replace will replace the target #default-format with the template, in this case it is just the form:

<turbo-stream action="replace" target="default-format">
  <template>
    <form>
      <!-- ... -->
    </form>
  </template>
</turbo-stream>

Which means <turbo-frame> goes away:

<!-- target          identified by id -->
<!-- v               v                -->
    <turbo-frame id="default-format"></turbo-frame>

<!-- is replaced by -->
    <form></form>

<!-- end result -->
    <form></form>

There is no #default-format for the stream to replace the second time.


turbo_stream.update action keeps the target and only updates the contents.

<!-- target          identified by id -->
<!-- v               v                -->
    <turbo-frame id="default-format"></turbo-frame>

<!-- target content is updated with -->
    <form></form>

<!-- end result -->
    <turbo-frame id="default-format">
      <form></form>
    </turbo-frame>

The target of the turbo-stream can be anything, not just turbo-frame:

<!-- unless you're doing something else with this frame, 
     there is no need for it -->
<%= turbo_frame_tag "format-list" do %>
  <%= render @book_formats %>
<% end %>

<!-- just an `id` is enough for turbo-stream -->
<div id="format-list">
  <%= render @book_formats %>
</div>

https://turbo.hotwired.dev/reference/streams

Alex
  • 16,409
  • 6
  • 40
  • 56
  • WOW! Yes, I read the documentation but I didn't understand it. Very clearly explained, thanks a lot. – tkhobbes Aug 18 '22 at 11:39