Astuce Laravel 5.4 : Comment gérer les requêtes ajax (GET, POST) et les tokens ?

Faire un site web aujourd’hui, c’est aussi savoir ne pas recharger la page à chaque action d’utilisateur, pour cela on a JavaScript, bien connu depuis des décennies maintenant. Mais comment l’utiliser avec Laravel ?

Cas d’un système de vote par article

Pour les besoins de notre page, on va ajouter un système de vote par article. Notre but est de voter pour promouvoir un article sans devoir recharger la page du dit article.

Note : Dans cet exemple, je n’utilise que la librairie jQuery mais rien ne nous empêche d’utiliser Angular ou un autre framework JS. Ici je reste le plus simple possible pour faciliter la compréhension.

Dans la vue de notre article, on va ajouter le manager JavaScript de nos posts que l’on aura créé dans le dossier « public/js/posts.js » :

/* resources/views/post.blade.php */
@extends('layouts.app')
@section('content')

   /*...*/

   <script src="{{ asset('js/posts.js') }}"></script>

@endsection

Et créé notre manager simple et lisible même si on utilise quasiment du JS pur :

/* public/js/posts.js */
var posts_manager = function () {

   this.onclickUpVote = function(postId){
      $.ajax({
         type: "POST",
         url: "/laravel-test/public/posts/" + postId + "/up_vote",
         data: "",
         dataType: "json",
         success: function (response) {
            $('#up_vote').text(response.vote);
         }
      });
   }

}

var POSTS_MANAGER = null;
if (!POSTS_MANAGER) {
 POSTS_MANAGER = new posts_manager();
}

Et dans notre vue, on va pouvoir appeler notre méthode "POST_MANAGER.onclickUpVote" :

/* resources/views/post.blade.php */
@extends('layouts.app')
@section('content')

  <div class="container">
     <div class="row question-list-item">
        <div class="col-md-2">
           <div class="row text-center vote">
              <i class="fa fa-chevron-up" aria-hidden="true" 
                  onclick="POSTS_MANAGER.onclickUpVote({{ $post->id }}')"></i>
              <p id="up_vote">{{ $post->up_vote }}</p>
           </div>
        </div>
        <div class="col-md-10 post-container">
           <h3>
              <a href="{{ URL::action('Posts\PostsController@create', $post->id) }}">{{ $post->title }}</a>
           </h3>
           <p>{{ $post->content }}</p>
           <i>{{ $post->user->name }}</i>
        </div>
      </div>
  </div>

<script src="{{ asset('js/posts.js') }}"></script>

@endsection

Pour éviter les erreurs CSRF lié au token, on vérifie que notre page, ici notre « app.blade.php » puisque notre page extends de layouts.app, contient bien la balise meta suivante dans son header :

/* resources/views/layout/app.blade.php */
/* ... */
 <!-- CSRF Token -->
 <metaname="csrf-token"content="{{ csrf_token() }}">
/* ... */

Et paramétrer les requêtes Ajax de notre application pour que le token contenu dans la balise meta soit automatiquement ajouté au header des requêtes Ajax. Ainsi, on pourra créer nos requêtes Ajax comme d’habitude, sans se soucier de passer le token manuellement.

/* public/js/settings.js */
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

Ce nouveau fichier settings.js est ajouté à mon layout app.blade.php, après l’ajout du script app.js :

/* ... */
<script src="{{ asset('js/app.js') }}"></script>
<script src="{{ asset('js/settings.js') }}"></script>
/* ... */

Maintenant, on va ajouter la route pour notre requête Ajax :

/* routes/web.php */
/* ... */
//posts
Route::get('/posts', 'Posts\PostsController@list')->name('posts.list');
Route::get('/posts/create', 'Posts\PostsController@create')->name('posts.create');
Route::put('/posts/create', 'Posts\PostsController@insert')->name('posts.insert');
Route::get('/posts/list', 'Posts\PostsController@list')->name('posts.list');
Route::get('/posts/{id}/read', 'Posts\PostsController@read')->name('posts.read');
Route::post('/posts/{id}/up_vote', 'Posts\PostsController@update_vote_up')->name('posts.vote.up');

On va créer la méthode correspondante dans notre PostsController.php :

/* app/Http/Controller/PostsController.php */
/* ... */
public function update_vote_up($id){
   $post = Post::where('id', $id)->firstOrFail();
   $up_vote = (int)$post->up_vote;
   $updates = array();
   $updates['up_vote'] = $up_vote + 1;
   $post->update($updates);
   return response()->json(['vote' => $updates['up_vote']]);
}
/* ... */

Explications… On récupère l’article en question, on récupère les votes existants, on ajoute 1 vote et on met à jour en base de données. Au lieu de retourner une vue comme d’habitude ou de rediriger la page, on va retourner une réponse au format JSON.

Note : Il faut que notre colonne « up_vote » soit bien ajouté au tableau des variables modifiables dans notre modèle Post.php

/* app/Models/Post.php */
/* ... */
protected $fillable = [
   'title', 'content', 'user_id', 'up_vote'
];
/* ... */

On pourra donc mettre à jour notre vue et afficher le nouveau vote fraîchement comptabilisé sans avoir à recharger la page, ce qui est plus confortable pour le visiteur ! Dans le success de notre requête Ajax, on récupère la balise p qui contenait notre ancien compteur de vote et on le met à jour.

/* public/js/posts.js */
/* ... */
this.onclickUpVote = function(postId){ 
   $.ajax({ 
      type: "POST", 
      url: "/laravel-test/public/posts/" + postId + "/up_vote", 
      data: "", 
      dataType: "json", 
      success: function (response) { 
         $('#up_vote').text(response.vote); 
      } 
   }); 
}
/* resources/views/post.blade.php */
/* ... */
<div class="row text-center vote">
   <i class="fa fa-chevron-up" aria-hidden="true" 
      onclick="POSTS_MANAGER.onclickUpVote({{ $post->id }}')"></i>
   <p id="up_vote">{{ $post->up_vote }}</p>
</div>
/* ... */

On pourra donc avoir des éléments avec lesquels les utilisateurs pourrons interagir sans que cela ne provoque un rechargement de la page 😉

N’hésitez pas à laisser vos commentaires, questions et suggestions d’amélioration de cet article !

Une réflexion au sujet de « Astuce Laravel 5.4 : Comment gérer les requêtes ajax (GET, POST) et les tokens ? »

  1. Ping : Laravel | Pearltrees

Laisser un commentaire