Esse post é bem rápido e simples, pra seguir ele é necessário conhecimento básico em Ruby on Rails. Se você já manja muito de Rails e Stimulus, esse post não é para você! (por isso a #beginners XD).
De toda forma, gostaria de deixar registrado como aprendi a fazer uma simples navbar responsiva para um projetinho Rails 7 em que estou trabalhando.
Configurações
Ruby 3.3.0
Rails 7.1.3
gem bulma-rails na versão 0.9.4
gem "stimulus-rails"
Pequenos detalhes
Pra esse exemplo estou usando o código "Basic navbar" do Bulma CSS.
O problema que eu quero resolver com esse post é o uso de javascript no projeto Rails.
Para abrir e fechar a navbar, a documentação do Bulma CSS sugira que eu use esse código:
document.addEventListener('DOMContentLoaded', () => { // Pega todos os elementos "navbar-burger" const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); // Adiciona o evento de click em cada um deles $navbarBurgers.forEach( el => { el.addEventListener('click', () => { // Pega o alvo a partir do atributo "data-target" que vem no navbar const target = el.dataset.target; const $target = document.getElementById(target); // Alternar a classe "is-active" do Bulma CSS tanto no "navbar-burger" e no "navbar-menu" el.classList.toggle('is-active'); $target.classList.toggle('is-active'); }); }); }); A questão é que eu estava tendo dificuldades para adicionar isso na minha aplicação e sempre que eu trocava de rota, a navbar parava de abrir. O código só funcionava uma vez.
Quando perguntei no grupo do Telegram Ruby Brasil a respeito, me foi sugerido que eu fizesse um "controller do Stimulus"
Eu já tinha ouvido falar a respeito dessa ferramenta, mas ainda não tinha tentado usá-la; então fui aprender.
Stimulus
Sem me aprofundar muito no assunto, o Stimulus é uma "framework de Javascript modesta para o HTML que você já tem". Ou seja, ele é uma ferramenta que te ajuda a manipular seu documento HTML usando javascript e alguns atributos especiais nas tags HTML.
Como eu quero fazer um controller relacionado ao navbar, eu criei dentro da pasta app/javascript/controllers o arquivo navbar_controller.js.
Inicializei ele da forma padrão:
import { Controller } from "@hotwired/stimulus" export default class extends Controller {} Depois disso, criei uma partial navbar com o código do Basic Navbar do Bulma CSS
app/views/layouts/_navbar.html.erb
<nav class="navbar is-transparent container is-max-desktop"> <div class="navbar-brand"> <a class="navbar-item" href="/"> <img src="https://bulma.io/images/bulma-logo.png" alt="Bulma: a modern CSS framework based on Flexbox" width="112" height="28"> </a> <div class="navbar-burger"> <span></span> <span></span> <span></span> </div> </div> <div class="navbar-menu"> <div class="navbar-start"> <a class="navbar-item" href="/"> Início </a> <a class="navbar-item" href="/books"> Catálogo </a> <a class="navbar-item" href="/"> Assinatura </a> <a class="navbar-item" href="/books/new"> Adicionar livro </a> </div> <div class="navbar-end"> <div class="navbar-item"> <div class="field is-grouped"> <p class="control"> <a class="bd-tw-button button"> <span> Entrar </span> </a> </p> <p class="control"> <a class="button is-primary"> <span>Criar conta</span> </a> </p> </div> </div> </div> </div> </nav> O que precisamos fazer é adicionar a classe "is-active" à div com a classe "navbar-menu" quando a div "navbar-burger" receber um click, e depois remover a classe "is-active" quando o burger receber outro click.
Dessa forma, precisamos estabelecer para o navbar_controller qual é a "área" que ele vai atuar, ou seja, qual elemento vai ser controlado ou gerenciado.
Para isso, colocamos o atributo data-controller="navbar" em nosso navbar, ficando assim:
<nav class="navbar is-transparent container is-max-desktop" data-controller="navbar">
Depois, precisamos definir qual elemento vai possuir a ação gerenciada pelo controller. Como queremos que seja o navbar-burger, colocamos um atributo chamado data-action, cujo valor tem o seguinte formado: ação->controller#função
O navbar burger fica assim:
<div class="navbar-burger" data-action="click->navbar#toggle">
E então precisamos ver qual é o elemento que será afetado por essa ação. Nosso "alvo" é o menu em si. Então, devemos colocar o atributo data-controller-target, substituindo "controller" pelo nome dado ao nosso controller. Ou seja:
<div class="navbar-menu" data-navbar-target="menu">
Mas aí você se pergunta: que diabo de função é essa?
E eu te respondo!
Lá no nosso navbar_controller.js, vamos adicionar a função toggle(), que é a função que vai ser ativada quando houver um click no navbar-burger.
A função vai pegar o elemento "alvo" (target) e fazer a alternação na classe "is-active". Só que para pegar nosso elemento alvo, precisamos registrá-lo.
app/javascript/controllers/navbar_controller.js
import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["menu"]; } Todos nossos targets devem ser registrados dentro desse array, passando o valor que colocamos no atributo "data-navbar-target".
Dessa forma, conseguiremos acessar nosso target a partir da expressão this.menuTarget.
Assim, conseguiremos acessar toda a estrutura HTML desse elemento, podendo inclusive manipular suas classes! E, portanto, resolvendo nosso problema:
import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["menu"]; toggle() { this.menuTarget.classList.toggle('is-active'); } } Com isso, conseguimos reduzir todas aquelas 7 linhas de JS puro em 3 atributos HTML e uma função simples com Stimulus.
Eu achei bem divertido fazer isso, é um código extremamente simples e fico imaginando as diversas possibilidades mais complexas as quais essa ferramenta pode nos ajudar a atuar.
Espero que essa publicação seja útil a alguém e é isso!
Para mais exemplos de Stimulus recomendo fortemente sua documentação e as aulas do The Odin Project!

Top comments (0)