Skip to content

Chapitre 5.3 : Intégration de JavaScript dans les vues Laravel

Temps d'étude : 50 minutes


1. Deux approches de JavaScript sur le web

Jusqu'à présent, nous avons travaillé avec le Server-Side Rendering (SSR) — le serveur (Laravel) générait le HTML prêt (via Blade) et l'envoyait au navigateur. C'est excellent pour le SEO et un premier chargement rapide.

Maintenant, nous allons ajouter des Client-Side Interactions — le navigateur, une fois la page chargée, exécutera du code JavaScript pour :

  • Envoyer des requêtes à notre API sans recharger la page.
  • Mettre à jour dynamiquement des parties de la page (par exemple, ajouter une nouvelle planète à la liste).
  • Afficher des notifications et des fenêtres modales.

💡 Analogie spatiale :

Imaginez que le SSR est l'obtention d'une carte complète d'un système stellaire, imprimée au centre de contrôle (serveur). Vous voyez tous les objets au moment de l'impression.

Le Client-Side JS est votre tablette personnelle (navigateur) qui se connecte en temps réel aux satellites (API) et met à jour la position des objets sur votre carte, sans demander une nouvelle carte papier au centre de contrôle.


2. Où stocker et comment inclure le code JS

Comme nous l'avons déjà établi, tous les actifs publics (CSS, JS, images) doivent se trouver dans le dossier public.

Structure correcte :

  1. Fichiers source : Tout votre code JS principal doit se trouver dans public/js/. Par exemple, public/js/planets.js.
  2. Inclusion dans Blade : Utilisez l'aideur asset() pour générer l'URL correcte.

Exemple d'inclusion dans le gabarit layouts/app.blade.php :

<!DOCTYPE html>
<html>
<head>
    {{-- ... --}}
</head>
<body>
    {{-- ... header et main ... --}}

    <footer>
        <p>&copy; {{ date('Y') }} Space Command.</p>
    </footer>

    {{-- Il est préférable d'inclure les scripts à la fin du corps pour accélérer le rendu de la page --}}
    <script src="{{ asset('js/planets.js') }}"></script>
    @stack('scripts') {{-- Nous créons un "slot" pour les scripts d'une page spécifique --}}
</body>
</html>

  • @stack('scripts') est une directive Blade puissante. Elle permet aux vues enfants de "pousser" leur propre code JS à cet endroit. C'est utile lorsqu'une page nécessite un script unique et qu'une autre non.

3. Exemple : Bouton "Supprimer" avec confirmation

Ajoutons un bouton "Supprimer" pour chaque planète sur la page de liste des planètes (planets/index.blade.php), qui fonctionnera via JavaScript et l'API Fetch.

Étape 1 : Ajout du bouton dans resources/views/planets/index.blade.php

Modifiez la carte de la planète en ajoutant un bouton avec des attributs data :

{{-- ... à l'intérieur de la boucle @forelse ... --}}
<div class="planet-card" id="planet-card-{{ $planet->id }}">
    <h3>{{ $planet->name }}</h3>
    <p>Système solaire : {{ $planet->solar_system }}</p>
    <p>Diamètre : {{ number_format($planet->size_km, 0, '.', ' ') }} km</p>
    <a href="/planets/{{ $planet->id }}">En savoir plus &rarr;</a>
    <button class="delete-btn" data-id="{{ $planet->id }}" data-url="/api/planets/{{ $planet->id }}">
        Désaffecter
    </button>
</div>
<!-- ... Avant la balise de fermeture body ... -->
<script src="{{ asset('js/planets.js') }}" defer></script>

  • id="planet-card-{{ $planet->id }}" — ID unique pour toute la carte, afin que nous puissions la supprimer du DOM.
  • data-id et data-url — un moyen pratique de transmettre des données de PHP (Blade) à JavaScript.

Étape 2 : Écriture de la logique JavaScript

Créez le fichier public/js/planets.js et ajoutez-y le code suivant :

document.addEventListener('DOMContentLoaded', () => {
    // Trouver tous les boutons "Supprimer"
    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(`Êtes-vous sûr de vouloir désaffecter la planète avec l'ID ${planetId} ? Cette action est irréversible.`)) {
                return; // L'utilisateur a cliqué sur "Annuler"
            }

            try {
                // Envoyer une requête DELETE à notre API
                const response = await fetch(apiUrl, {
                    method: 'DELETE',
                    headers: {
                        'Accept': 'application/json',
                        // Plus tard, nous ajouterons le jeton CSRF ici
                    }
                });

                if (response.status === 204) { // 204 No Content - suppression réussie
                    // Supprimer la carte de la planète de la page
                    const cardToRemove = document.getElementById(`planet-card-${planetId}`);
                    if (cardToRemove) {
                        cardToRemove.remove();
                    }
                    alert('La planète a été désaffectée avec succès.');
                } else {
                    // Si l'API a renvoyé une erreur
                    const errorData = await response.json();
                    alert(`Erreur : ${errorData.message || 'Impossible de supprimer la planète.'}`);
                }
            } catch (error) {
                console.error('Erreur lors de l\'envoi de la requête :', error);
                alert('Une erreur réseau est survenue. Veuillez réessayer.');
            }
        });
    });
});

Maintenant, si vous rafraîchissez la page /planets, vous verrez les boutons "Désaffecter", et en cliquant dessus, notre code JavaScript se déclenchera !


4. Transmission de données de Blade vers JavaScript

Parfois, il est nécessaire de transmettre à JS non pas une simple chaîne de caractères, mais un tableau ou un objet entier.

Méthode incorrecte (vulnérable) :

let planets = {{ $planets }}; // Cela entraînera une erreur de syntaxe et est dangereux.

Méthode correcte (via JSON) : Utilisez la directive @json. Elle convertit en toute sécurité un tableau/objet PHP en un objet JSON valide.

Exemple dans planets/index.blade.php :

@extends('layouts.app')
{{-- ... --}}
@section('content')
    {{-- ... --}}
@endsection

@push('scripts') {{-- Nous "poussons" notre script dans le slot @stack('scripts') du gabarit --}}
<script>
    // Laravel convertit en toute sécurité la collection $planets en un tableau JSON
    const planetsData = @json($planets);

    // Maintenant, nous pouvons travailler avec ce tableau en JS
    console.log('Données sur les planètes transmises depuis Blade :', planetsData);
    alert(`${planetsData.length} planètes chargées !`);
</script>
@endpush

  • @push('scripts') place le contenu à l'intérieur de @stack('scripts') dans layouts/app.blade.php. Cela permet d'ajouter des scripts uniquement aux pages où ils sont réellement nécessaires.

Quiz de consolidation

1. Où les fichiers JS et CSS publics doivent-ils être stockés dans un projet Laravel ?

2. Quel aideur Blade est utilisé pour générer correctement l'URL des actifs (JS, CSS) ?

3. Que fait la paire de directives `@push('scripts')` / `@stack('scripts')` ?

4. Comment transmettre en toute sécurité un tableau PHP `$data` à JavaScript depuis Blade ?

5. Pourquoi est-il recommandé d'inclure les scripts JS à la fin de la balise body ?


🚀 Conclusion du chapitre :

Vous avez appris à donner vie aux pages Blade statiques en ajoutant de la logique côté client. Compétences clés :

  • Organisation et inclusion correctes des fichiers JS dans un projet Laravel.
  • Utilisation des attributs data-* pour transmettre des données de HTML à JS.
  • Interaction dynamique avec l'API via Fetch sans rechargement de page.
  • Transmission sécurisée des variables PHP à JavaScript à l'aide de la directive @json.
  • Organisation des scripts avec @push et @stack. Vos "panneaux de contrôle" sont devenus interactifs. Cependant, nos requêtes de modification (POST, PUT, DELETE) sont désormais vulnérables. Dans le chapitre suivant, nous ajouterons un mécanisme de protection crucial : les jetons CSRF.