Skip to content

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:

  1. Arquivos Originais: Todo o seu código JS principal deve estar em public/js/. Por exemplo, public/js/planets.js.
  2. 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>&copy; {{ 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 &rarr;</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 e data-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):

let planets = {{ $planets }}; // Isso levará a um erro de sintaxe e é inseguro

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') em layouts/app.blade.php. Isso permite adicionar scripts apenas nas páginas onde eles são realmente necessários.

Quiz para fixação

1. Onde os arquivos JS e CSS públicos devem ser armazenados em um projeto Laravel?

2. Qual helper do Blade é usado para a geração correta de URLs para ativos (JS, CSS)?

3. O que o par de diretivas `@push('scripts')` / `@stack('scripts')` faz?

4. Como passar com segurança um array PHP `$data` para JavaScript do Blade?

5. Por que é recomendado incluir scripts JS no final da tag body?


🚀 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.