Capítulo 5.3: Incorporando JavaScript em Laravel Views
Tempo de estudo: 50 minutos
1. Duas abordagens para JavaScript na Web
Até agora, trabalhamos com Server-Side Rendering (SSR) — o servidor (Laravel) gerava o HTML pronto (via Blade) e o enviava para o navegador. Isso é excelente para SEO e carregamento rápido da primeira página.
Agora adicionaremos Client-Side Interactions — o navegador, após carregar a página, executará código JavaScript para:
- Enviar requisições à nossa API sem recarregar a página.
- Atualizar dinamicamente partes da página (por exemplo, adicionando um novo planeta à lista).
- Exibir notificações e janelas modais.
💡 Analogia Espacial:
Imagine que SSR é receber um mapa completo do sistema estelar, impresso no Centro de Controle de Missões (servidor). Você vê todos os objetos no momento da impressão.
Client-Side JS é o seu tablet pessoal (navegador), que se comunica em tempo real com os satélites (API) e atualiza a posição dos objetos no seu mapa, sem solicitar um novo mapa em papel do CCM.
2. Onde armazenar e como incluir o código JS
Como já descobrimos, todos os ativos públicos (CSS, JS, imagens) devem estar na pasta public
.
Estrutura Correta:
- Arquivos Originais: Todo o seu código JS principal deve estar em
public/js/
. Por exemplo,public/js/planets.js
. - Inclusão no Blade: Use o helper
asset()
para gerar o URL correto.
Exemplo de inclusão no layout layouts/app.blade.php
:
<!DOCTYPE html>
<html>
<head>
{{-- ... --}}
</head>
<body>
{{-- ... header e main ... --}}
<footer>
<p>© {{ date('Y') }} Space Command.</p>
</footer>
{{-- Scripts são melhores para incluir no final do body para acelerar a renderização da página --}}
<script src="{{ asset('js/planets.js') }}"></script>
@stack('scripts') {{-- Criamos um "slot" para scripts de uma página específica --}}
</body>
</html>
@stack('scripts')
— esta é uma diretiva Blade poderosa. Ela permite que as views filhas "empurrem" seu próprio código JS para este local. Isso é útil quando uma página precisa de um script exclusivo e outra não.
3. Exemplo: Botão "Excluir" com confirmação
Vamos adicionar à página de lista de planetas (planets/index.blade.php
) um botão "Excluir" para cada planeta, que funcionará via JavaScript e Fetch API.
Passo 1: Adicione o botão em resources/views/planets/index.blade.php
Modifique o cartão do planeta, adicionando um botão com data-atributos:
{{-- ... dentro do ciclo @forelse ... --}}
<div class="planet-card" id="planet-card-{{ $planet->id }}">
<h3>{{ $planet->name }}</h3>
<p>Sistema Solar: {{ $planet->solar_system }}</p>
<p>Diâmetro: {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
<a href="/planets/{{ $planet->id }}">Saber mais →</a>
<button class="delete-btn" data-id="{{ $planet->id }}" data-url="/api/planets/{{ $planet->id }}">
Descomissionar
</button>
</div>
<!-- ... Antes da tag de fechamento do body ... -->
<script src="{{ asset('js/planets.js') }}" defer></script>
id="planet-card-{{ $planet->id }}"
— ID único para o cartão inteiro, para que possamos removê-lo do DOM.data-id
edata-url
— uma maneira conveniente de passar dados do PHP (Blade) para o JavaScript.
Passo 2: Escreva a lógica JavaScript
Crie o arquivo public/js/planets.js
e adicione o seguinte código:
document.addEventListener('DOMContentLoaded', () => {
// Encontra todos os botões "Excluir"
const deleteButtons = document.querySelectorAll('.delete-btn');
deleteButtons.forEach(button => {
button.addEventListener('click', async (event) => {
const planetId = event.target.dataset.id;
const apiUrl = event.target.dataset.url;
if (!confirm(`Tem certeza de que deseja descomissionar o planeta com ID ${planetId}? Esta ação é irreversível.`)) {
return; // O usuário clicou em "Cancelar"
}
try {
// Envia uma requisição DELETE para nossa API
const response = await fetch(apiUrl, {
method: 'DELETE',
headers: {
'Accept': 'application/json',
// Mais tarde adicionaremos o token CSRF aqui
}
});
if (response.status === 204) { // 204 No Content - exclusão bem-sucedida
// Remove o cartão do planeta da página
const cardToRemove = document.getElementById(`planet-card-${planetId}`);
if (cardToRemove) {
cardToRemove.remove();
}
alert('Planeta descomissionado com sucesso.');
} else {
// Se a API retornou um erro
const errorData = await response.json();
alert(`Erro: ${errorData.message || 'Não foi possível descomissionar o planeta.'}`);
}
} catch (error) {
console.error('Erro ao enviar a requisição:', error);
alert('Ocorreu um erro de rede. Tente novamente.');
}
});
});
});
Agora, se você atualizar a página /planets
, aparecerão os botões "Descomissionar", e ao clicar neles, nosso código JavaScript será executado!
4. Passando dados de Blade para JavaScript
Às vezes é necessário passar para o JS não apenas uma string, mas um array ou objeto inteiro.
Maneira incorreta (vulnerável):
Maneira correta (via JSON):
Use a diretiva @json
. Ela converte com segurança um array/objeto PHP em um objeto JSON válido.
Exemplo em planets/index.blade.php
:
@extends('layouts.app')
{{-- ... --}}
@section('content')
{{-- ... --}}
@endsection
@push('scripts') {{-- "Empurra" nosso script para o slot @stack('scripts') no layout --}}
<script>
// Laravel converte com segurança a coleção $planets em um array JSON
const planetsData = @json($planets);
// Agora podemos trabalhar com este array em JS
console.log('Dados dos planetas passados do Blade:', planetsData);
alert(`Carregados ${planetsData.length} planetas!`);
</script>
@endpush
@push('scripts')
insere o conteúdo dentro de@stack('scripts')
emlayouts/app.blade.php
. Isso permite adicionar scripts apenas nas páginas onde eles são realmente necessários.
Quiz para fixação
🚀 Resumo do capítulo:
Você aprendeu a dar vida a páginas Blade estáticas, adicionando lógica do lado do cliente. Habilidades essenciais:
- Organização e conexão corretas de arquivos JS em um projeto Laravel.
- Uso de atributos
data-*
para transferir dados de HTML para JS. - Interação dinâmica com API usando Fetch sem recarregar a página.
- Transferência segura de variáveis PHP para JavaScript usando a diretiva
@json
. - Organização de scripts usando
@push
e@stack
.
Seus "painéis de controle" tornaram-se interativos. No entanto, nossas requisições de modificação (POST, PUT, DELETE) estão vulneráveis agora. No próximo capítulo, adicionaremos um mecanismo de proteção crucial — tokens CSRF.