hotwired/turbo

Feature request: Ability to target multiple frames

acetinick opened this issue · 8 comments

Currently Turbo frames is amazing at handling HTML updates back to the UI when specifying a single frame target to update on the page. In a lot of cases this is all you need however in more complex UI's, I find that we need to update many frames within the same page on the response.

Now we could solve this by using Turbo streams, however this often is not ideal to have to refactor things into lots of partials and write more stream update code in controller/view to perform the turbo stream replacements. Especially when you just looking to update counts or certain labels around the page, it adds extra steps.

Idea

We could borrow the concept from Stimulus which supports defining multiple controllers, to support defining multiple target frames in the data-turbo-target attribute, this will allow replacing multiple frames without needing any extra code in streams or refactoring simple parts of the page into partials.

<a data-turbo-method='delete' data-turbo-target="employee-positions employee-header">Delete</a>

image

In this situation we can easily wrap define a frame in the top called "employee-header" and another around the employee positions section called "employee-positions". Once deleting a row in the table, both frame targets will update automatically from on the same page response.

Thoughts?

this is neat I want to use it like this
the form in red could change the value inside the red border and also green border
but keep the yellow border untouched

image

<div class="max-w-2xl mx-auto px-4 sm:px-6 lg:max-w-7xl lg:px-8">
  <div class= "lg:grid lg:grid-cols-6 lg:gap-x-12 xl:gap-x-16">
    <div class="col-span-2">
      <%= form_with model: @selling, 
      data: { 
        turbo_frame: "selling-information", 
        turbo_action: "advance"
      } do |form| %>
        <div  class="border-8 border-red-600">
          <turbo-frame id="selling-information">
            <%= render "sellings/checkouts/informasi_pelanggan", form: form %>
            <%= render "sellings/checkouts/jenis_pembayaran", form: form %>
          </turbo-frame>
        </div>
      <% end %>
    </div>
    <div class="col-span-4">
      <div class="border-8 border-yellow-500">
        <%= render "sellings/checkouts/table_item" %>
      </div>
      <div class="border-8 border-green-600">
        <%= render "sellings/checkouts/total_belanja" %>
      </div>
    </div>
  </div>
</div>

I have a similar scenario where based on a form result, that form could trigger the re-render of 2 different frames, if the result is a failure I need to render the errors above the form and if the result is a success I want to add the result to a different frame in the same UI.

I think the suggested approach would work for me, basically telling the backend that it could return employee-positions OR employee-header.

data-turbo-target="employee-positions employee-header"

If this makes sense, I would love to work on a PR to introduce this change

miii commented

While turbo streams seems to be the official way to solve this, we also encountered the issue where some refactoring was required to make that work. In my opinion, having the ability to target multiple frames would be a great DX improvement to progressively enhance the user experience in a quick way and later implement stream-formatted responses to further optimize the app.

In the meantime, I've created a package which hooks into Turbo and emulates the behavior suggested here.
https://github.com/miii/turbo-multiple-frame-targeting

Hey folks, does anybody knows if there is any news about this thread?

💯 We've also been dealing with this restriction for the past year. We've created an inelegant work-around for targeting multiple frames. Is there any specific reason for not supporting multiple frames in and being forced to switch to turbo stream?

I think scenarios like the ones described in this thread are great candidates for the new morphing feature in Turbo 8.

It's already in Beta. Give it a go! It'll probably remove a whole category of problems you're dealing with.

I have this same issue, and I am trying to solve it by using the new morphing feature in Turbo 8; but I'm running into one big limitation.

If you want to use Turbo 8 morphing to update multiple turbo-frames then here is how you do it:

Make sure your form submission is intentionally break out of the turbo frame by ensuring the action the user is taking has a target _top. Then, wherever you are POSTing to, ensure you are redirecting back to the same route where the form was submitted. When you do this, a morph will happen. It's great.

In other words, if you have multiple turbo frames, you intentionally don't even think about which frames you want to be updated. The whole page will be rendered and because redirect_to goes back to the same route you started with, then a Page Refresh action is used which will do a morph.

But I am finding that sometimes I want a GET to update multiple frames. Or sometimes I am doing a form POST but there are reasons why I do not want to redirect back to the same route that the user was on when they submitted the form. Yet I still want a Page Refresh morph to be used. I have not yet found a work around for this. I thought I could add data-turbo-action="morph" to a link or a form in order to explicitly use a Page Refresh morph, but it doesn't work like that.

Hi all, at least for now, it's not in our plans to add something like this to the API. The best tool to solve this in these cases are Turbo streams or now using morphing and page refreshes. Closing this for now