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)