How can I make use of turbo frames correctly?

821 views Asked by At

I have the next "controllers/pages_controller.rb":

class PagesController < ApplicationController
  def home
  end

  def stack
  end

  def about
  end
end

I have the next "routes":

Rails.application.routes.draw do
  root "pages#home"
  get 'home', to: 'pages#home'
  get 'about', to: 'pages#about'
  get 'stack', to: 'pages#stack'
  get 'projects', to: 'projects#index'
end

I have the next "layouts/application.html.erb":

<!DOCTYPE html>
<html>
  <head>
    <title>Daniel Enqz</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>
  </head>

  <body>
    <main class="container mx-auto mt-14 px-5">
      <%= render 'shared/breadcrumb' %>
      <div class="mt-10 h-screen grid content-start">
        <%= turbo_frame_tag "main" do %>
          <%= yield %>
        <% end %>
      </div>
    </main>
  </body>
</html>

I have the next "views/shared/_breadcrumb.html.erb":

<nav aria-label="breadcrumb" data-controller="breadcrumb" id="breadcrumb">
  <ol class="inline-flex items-center space-x-4 py-2 text-lg font-medium">
    <li class="inline-flex items-center">
      <a href="" class="text-slate-900 hover:text-cyan-400">@dan </a>
    </li>
    <li class="inline-flex items-center space-x-4">
      <span class="text-secondary-400">/</span>
      <%= link_to "Home", home_path, class: "text-slate-400", data: { action: "breadcrumb#toggle", turbo_frame: "main" } %>
    </li>
    <li class="inline-flex items-center space-x-4" aria-current="page">
      <span class="text-secondary-400">/</span>
      <%= link_to "Projects", projects_path, class: "text-slate-400", data: { action: "breadcrumb#toggle", turbo_frame: "main" } %>
    </li>
    <li class="inline-flex items-center space-x-4" aria-current="page">
      <span class="text-secondary-400">/</span>
      <%= link_to "Stack", stack_path, class: "text-slate-400", data: { action: "breadcrumb#toggle", turbo_frame: "main" } %>
    </li>
    <li class="inline-flex items-center space-x-4" aria-current="page">
      <span class="text-secondary-400">/</span>
      <%= link_to "About", about_path, class: "text-slate-400", data: { action: "breadcrumb#toggle", turbo_frame: "main" } %>
    </li>
  </ol>
</nav>

I have the next "views/pages/about.html.erb":

<div class="flex flex-col">
  <h1>Hello</h1>
<div>

I want that when the user click on the about link in _breadcrumb.html.erb, the about.html.erb page hets rendered in <%= yield %>, of course using turbo frames and avoid reloading the page.

Im also getting this error in console:

Response has no matching <turbo-frame id="main"> element
1

There are 1 answers

0
max On

You don't actually need Turbo Frames here in the first place. What you want is just Turbo Drive and its enabled by default on all links.

Drive is used when you want to visit another page and update the page history. This works very much like Turbolinks which Turbo evolved from. It fetches the page with an XHR request and then replaces the contents of the document with the new page and uses history.pushState to update the browsers history. This avoids the overhead involved with rebuilding the entire document from scratch and negotiating all the assets (CSS, JS, images) again.

While you could use a Turbo Frame here YAGNI and it will actually result in a bad user experience / accessibility since visiting the different pages won't update the history (really annoying if the page where to refresh), doesn't update the title - etc.

Turbo frames are used when you want to decompose a page into separate frames that are updated independendly and do not constitute visiting another page. Like for example the classic comments form that prepends the comment to the list of comments without reloading. Think of this as modules that are embedded in a page rather then replacing the main contents of page.