Skip to content

Instantly share code, notes, and snippets.

@neilvcarvalho
Last active March 26, 2022 17:29
Show Gist options
  • Save neilvcarvalho/a643c7c578015a59861f6ebca4aada04 to your computer and use it in GitHub Desktop.
Save neilvcarvalho/a643c7c578015a59861f6ebca4aada04 to your computer and use it in GitHub Desktop.
Hotwire study annotations

Definitions

  • Stimulus: a lightweight JavaScript framework when it's not needed to do a roundtrip to the server
  • Turbo Drive: automatically captures any link, merges the already loaded header to the response header and replaces the loaded body with the response body
  • Turbo Frames: replaces only a specific part of the body
  • Turbo Streams: handles multiple responses, like appending something or replacing something on the body

Turbo Frames

You need to wrap a section of your view with a turbo_frame_tag. It can accept a model object, with which Rails automatically infers its name. Or you can use dom_id with the model object.

Just having a turbo-frame element on the response is enough to have Turbo Frames replace only that part of the application. However, it's possible to render only the changed part, and Turbo Frames will take care of the rest.

Important: it's not possible to place a turbo frame inside of a HTML table element, as it's not a valid element inside a table. The workaround is to use a HTML div instead and style it as a table.

You may encounter a situation in which you place a link inside a frame, but the content should replace the whole page. To "break out" of a frame, you need to add a data-turbo-frame element on this link, as in link_to object, data: { turbo_frame: "_top" }. This _top value is a special value that means the parent frame of that frame the link is in - or the whole document if there aren't any other frames. It can also be used to state which frame, other than the link is in, the link's response should replace.

Turbo Streams

Turbo Streams are a response type within Rails. You create a turbo_stream.erb file and it will be rendered back as you have typed. If you want to replace a turbo frame and update a div content, you can write a file as in:

<%= turbo_stream.replace @bait, @bait %>
<%= turbo_stream.update "tackle_box_items_count", current_user.tackle_box_items.size %>

turbo_stream.replace will first replace the @bait frame (which would be equivalent to dom_id(@bait) with the @bait html.erb partial), then, update the content of the div with id = tackle_box_items_count with the new count.

One caveat is a problem in that happens in other JavaScript technologies: updating a part of the HTML div via JavaScript will keep the content while you are on that page. However, if you hit the browser "back" button, any content updated via JavaScript will disappear, as it is cached in the Turbo Drive cache.

Add data-turbo-permanent to the HTML element you want to keep the value to get around it.

Turbo Streams do not work only with Turbo Frames. It will work with any HTML element with a unique id.

These are the possible actions:

  • replace: replaces the whole HTML element or Turbo Frame with the new content;
  • update: replaces the inner content of the HTML element or Turbo Frame with the new content.
  • append: adds the content to the end of the target element without changing its existing contents. For example, you want to add something to the bottom of a list.
  • prepend: adds the content to the beginning of the target element without changing its existing contents. For example, you want to add something to the top of a list
  • remove: removes the target element.
  • before: adds the content before the target element. For example, you want to put a high-priority item before a lower-priority item.
  • after: inserts the given content after the target element. For example, you want to put a February item after a January item.

To support HTML response, which is a desired thing when you practice unobtrusive JavaScript, you can add a respond_to block to your controller with a turbo_stream format, such as:

respond_to do |format|
  format.turbo_stream
  format.html { redirect_to baits_url }
end

Adding a format.turbo_stream with no block will render the default action - in this case, render the ACTION_NAME.turbo_stream.erb

Note: For simple responses, it's possible to render a turbo_stream action directly in the controller, as in:

render turbo_stream: turbo_stream.replace(@bait, @bait)

If you have a form that updates another section of the page when you submit it, such as a filter form, the active field will lose focus every time you hit submit. You might think about using turbo streams to empower this form and only update the results, but it's impossible to use turbo streams in GET requests.

This is a common situation, and there is a solution: using Turbo Frames. To do that, wrap your results in a Turbo Frame with a unique id, and then point your form to that frame:

form_with(url: search_path, data: { turbo_frame: "turbo_frame_unique_id", turbo_action: "advance" })

The turbo_action option will append the new URL to the browser history, making it possible to hit the "back" button and go to the previous results.

Stimulus

To create a Stimulus controller, you can either create the file manually then call the rails stimulus:manifest:update command, or create it via the Rails generator: rails g stimulus form. It will create an app/javascripts/controllers/form_controller.js file and automatically run the stimulus:manifest:update task.

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