Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inversion of layout responsibility between broadcaster and receiver for streams #708

Open
frivoal opened this issue Jan 5, 2025 · 0 comments

Comments

@frivoal
Copy link

frivoal commented Jan 5, 2025

Without turbo-streams, the view gets individual model objects or collections of them from the controller, and decides through templates how to arrange them.

With turbo-stream, the view gets to subscribe to updates to individual model objects or collections of them using turbo_stream_from, which makes a lot of sense, and those get broadcast from wherever you want (but typically the model), which also makes a lot of sense.

However, there's one thing that bugs me: it's the broadcaster, not the subscriber, that gets to decide if the item that gets added to a list is going to be appended or prepended (or inserted before or after).

The fact that it exists is fine, but that it's the only option bothers me:

  • this duplicates logic that already exists in the view. The view template already has logic on how to go about rendering (and thus ordering) items in a collection
  • different views can have a different preference about appending or prepending (or custom insertion), but since the positioning is decided at the broadcast level, (some) views will need to resort to custom js to reorganize what they got
  • In a view which normally uses :spacer_template between its items, an item inserted by turbo-stream will not be separated from its adjacent items by the usual spacer.
  • the broadcaster get a limited choice of where the item will be inserted, but if the view had somewhat fancier logic (sort items in some way, group subsets of items in some way), you're out of luck, unless you want to manually recreate that logic in js, in which case the decision to append or prepend becomes noise, since you're going to override it.

The system as it is designed works and is pretty convenient in typical cases, but I wonder if it could be extended to give more agency to the view to decide where things are going to go, possibly by using some set of options to turbo_stream_from. For instance:

  • <%= tubro_stream_from "thingies", insert_as: :prepend %> would let prepend turbo stream actions do their usual job, but would reinterpret append actions as being prepend (and vice versa for insert_as: :append)
  • <%= tubro_stream_from "thingies", spacer_template: "my_cool_spacer" %> would invoke the spacer template when the view is generated, store the output in some "display:none" element to keep it out of the way, and insert copies of it as needed when appending/prepending. (Deleting spacers alongside turbo-stream "Remove" actions would be a bit more fidly, but should be doable too.)

This is just an initial comment, so I'm not going to go too far down coming up with suggestions the specific API, but would it makes sense to try and go in this direction, keeping the decision to broadcast whether an addition / update / removal has happened to where it currently is, but giving more power to the view to decide how to display this new state of the world?

Or is the fact that I even want something like this at all a sign that I am misunderstanding the internal logic of turbo-streams?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant