Vários frames, uma página

Prévia grátis 4 min de leitura

No curso de nível Júnior "Hotwire: Turbo Drive & Frames", cada exemplo de frame tinha uma única função na página: a seção de imagens do editor de aulas, a thread de discussão. Nada diz que uma página só pode ter um. A lista de cursos do admin desta aplicação tem quatro frames independentes na mesma página, um por nível, e cada um pagina só a si mesmo.

Quatro frames, um por nível

app/views/admin/catalog/courses/index.html.erb, resumido: a tabela dentro de cada frame virou um comentário:

<% @result.levels_data.each do |level_name, data| %>
  <% pagy = admin_paginator(total_count: data.total_count, page_key: "#{level_name}_page", per_page: @per_page) %>
  <%= turbo_frame_tag "level-#{level_name}", data: { turbo_action: "advance" } do %>
    <div id="level-<%= level_name %>" class="mb-10 scroll-mt-24">
      <!-- tabela de cursos para este nível -->
    <% end %>
<% end %>

Um único each sobre quatro níveis (intern, junior, mid, senior) gera quatro elementos <turbo-frame> separados: level-intern, level-junior, level-mid e level-senior. Cada id vem do nome do nível, e cada frame envolve a própria tabela paginada. page_key: "#{level_name}_page" faz com que clicar em "próxima página" na tabela de intern não mexa no número de página da tabela de junior.

Por que um id dinâmico

Escrever turbo_frame_tag "level-intern", turbo_frame_tag "level-junior" e os demais à mão funcionaria igual. O "level-#{level_name}" dinâmico dentro de um loop é só DRY, o mesmo motivo de percorrer qualquer coleção em vez de repetir o código. O que importa é o que o id oferece. Um link de paginação gerado dentro do frame level-mid aponta para level-mid por padrão (o alvo restrito ao frame, regra daquele curso de nível Júnior). Então clicar em "próxima página" na tabela de nível mid troca só o conteúdo desse frame. As tabelas de intern, junior e senior ao lado não recarregam, não piscam e mantêm a própria paginação.

O que quebra se dois frames dividem um id

Um <turbo-frame id="..."> precisa ser único na página, como qualquer id de HTML. O Turbo depende disso em dois pontos. Quando uma resposta chega, ele copia o conteúdo do primeiro turbo-frame#id que encontra no HTML novo. Quando um link aponta um frame com data-turbo-frame, o Turbo o procura com document.getElementById, que devolve o primeiro elemento com aquele id. Então, se dois frames dividem um id, por um bug num loop ou por uma partial copiada com o id fixo, o segundo frame recebe o conteúdo do primeiro, e um link que mira o segundo atualiza o primeiro. Nada levanta erro. A página só mostra a tabela errada.

A view citada tem um caso menor disso. Cada frame envolve uma <div id="level-<%= level_name %>"> com o mesmo id do frame. Isso é HTML inválido, mas aqui não quebra nada. Um link de paginação dentro de um frame aponta para esse frame sem procurar id nenhum, e a busca na resposta pede turbo-frame#level-mid, que ignora a div. Os ids por nível continuam importando: os quatro níveis nunca colidem entre si, porque o nome do nível faz parte de cada id.

Pontos-chave

  • Nada limita uma página a um turbo frame. O índice de cursos do admin desta aplicação renderiza quatro, um por nível, com um único loop.
  • turbo_frame_tag "level-#{level_name}" gera um id diferente a cada volta. A paginação de cada frame (page_key: "#{level_name}_page") é contada à parte, então paginar a tabela de um nível nunca mexe na de outro.
  • O ganho de um id por nível é o alvo padrão: um link de paginação renderizado dentro do frame de um nível aponta para esse frame e deixa os outros da página em paz.
  • Ids de frame precisam ser únicos na página. Com dois frames dividindo um id, o Turbo usa a primeira ocorrência, e um frame recebe em silêncio o conteúdo do outro. A <div> interna desta view repete o id do frame, o que é HTML inválido, mas aqui não faz mal.
Aula 1 de 7 · grátis

Continue com a aula 2

Saindo com turbo-frame: _top

Como o alvo reservado _top leva um link ou formulário dentro de um frame para a página inteira.

Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.

Digite para buscar...