IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours pour apprendre à utiliser le framework Laravel 5.5

Plus loin avec Laravel


précédentsommaire

X. Vue.js

Dans ce chapitre, je vous propose de voir un exemple simple d'utilisation d'un framework JavaScript, en l'occurrence Vue.js, comme gestionnaire côté client associé à Laravel.

Je vous propose de démarrer le projet à partir de celui que j'ai élaboré dans cet article avec Materialize (lien direct de téléchargement). Il y a un lien dans l'article pour vous permettre de télécharger le projet de départ.

Comme exemple je vous propose une simple page qui permet de laisser une pensée pour les utilisateurs enregistrés, donc un simple texte qu'on a envie de partager.

Ce n'est pas une initiation à Vue.js : pour ça, vous pouvez vous référer à mon cours ici . C'est juste pour montrer son utilisation avec Laravel.

Mettez à jour le fichier .env selon votre configuration. Vous pouvez changer le nom de l'application :

 
Sélectionnez
APP_NAME=Pensées

Vous pouvez télécharger le code final de ce chapitre ici .

D'autre part, j'ai mis en ligne l'application en démonstration ici. Vous pouvez y laisser vos pensées Image non disponible

X-A. Le serveur

X-A-1. Données

On va donc créer une table pour mémoriser les pensées :

 
Sélectionnez
php artisan make:migration create_pensees_table

Changez ainsi le code de la méthode up :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
public function up()
{
    Schema::create('pensees', function (Blueprint $table) {
        $table->increments('id');
        $table->timestamps();
        $table->text('text');
        $table->integer('user_id')->unsigned();
        $table->foreign('user_id')->references('id')->on('users');
    });
}

puis lancez la migration :

 
Sélectionnez
php artisan migrate

Si tout s'est bien passé, vous devez avoir ces quatre tables :

Image non disponible

On va aussi créer le modèle :

 
Sélectionnez
php artisan make:model Pensee
Image non disponible

On va également établir les relations. Dans le modèle User on va avoir :

 
Sélectionnez
1.
2.
3.
4.
public function pensees()
{
    return $this->hasMany(Pensee::class);
}

et la réciproque dans le modèle Pensee :

 
Sélectionnez
1.
2.
3.
4.
public function user()
{
    return $this->belongsTo(User::class);
}

On va aussi penser à l'assignation de masse pour la création d'une pensée dans le modèle Pensee :

 
Sélectionnez
protected $fillable = [
    'text', 'user_id',
];

On va un peu remplir nos tables. On commence par créer un factory pour les pensées :

 
Sélectionnez
php artisan make:factory PenseeFactory --model=Pensee
Image non disponible

en complétant le code pour la génération du texte :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
<?php

use Faker\Generator as Faker;

$factory->define(App\Pensee::class, function (Faker $faker) {
    return [
        'text' => $faker->text,
    ];
});

Lancez tinker :

 
Sélectionnez
php artisan tinker

On va maintenant créer six utilisateurs avec chacun une pensée :

 
Sélectionnez
factory(App\User::class, 6)->create()->each(function ($u) {$u->pensees()->save(factory(App\Pensee::class)->make());});

Voilà, pour les données on est parés !

X-A-2. Contrôleur

On va créer un contrôleur de ressource pour nos pensées :

 
Sélectionnez
php artisan make:controller PenseeController --resource
Image non disponible

On va ne garder que les méthodes index, create et destroy :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PenseeController extends Controller
{
    public function index()
    {
        //
    }

    public function store(Request $request)
    {
        //
    }

    public function destroy($id)
    {
        //
    }
}

On va un peu coder tout ça en ajoutant une méthode initiale pour charger l'application :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Pensee;

class PenseeController extends Controller
{

    public function __construct()
    {
        $this->middleware('auth')->except('app', 'index');
    }

    public function app()
    {
        return view('pensees.index');
    }

    public function index(Request $request)
    {
        $pensees = Pensee::with('user')->latest()->get();

        $user = auth()->check() ? auth()->id() : 0;

        return response()->json([$pensees, $user]);
    }

    public function store(Request $request)
    {
        $request->validate([
            'text' => 'required|max:1000',
        ]);

        $request->merge(['user_id' => $request->user()->id]);

        $pensee = Pensee::create($request->all());

        return Pensee::with('user')->find($pensee->id);
    }

    public function destroy(Pensee $pensee)
    {
        $this->authorize('delete', $pensee);

        $pensee->delete();

        return response()->json();
    }
}

En gros, uniquement des choses qu'on a déjà vues dans ce cours…

La méthode merge permet d'ajouter des éléments à la requête.

X-A-3. Protections

On doit protéger les URL qui sont réservées aux utilisateurs authentifiés. On va donc ajouter un constructeur dans le contrôleur pour ajouter le middleware auth pour les méthodes concernées :

 
Sélectionnez
1.
2.
3.
4.
public function __construct()
{
    $this->middleware('auth')->except('app', 'index');
}

D'autre part, il faut faire en sorte que seul le rédacteur d'une pensée puisse supprimer cette pensée :

 
Sélectionnez
php artisan make:policy PenseePolicy --model=Pensee
Image non disponible

On va garder seulement la méthode delete avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
<?php

namespace App\Policies;

use App\User;
use App\Pensee;
use Illuminate\Auth\Access\HandlesAuthorization;

class PenseePolicy
{
    use HandlesAuthorization;

    public function delete(User $user, Pensee $pensee)
    {
        return $user->id == $pensee->user_id;
    }
}

Il faut l'enregistrer dans AuthServiceProvider :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
use App\ { Pensee, Policies\PenseePolicy };

class AuthServiceProvider extends ServiceProvider
{
    protected $policies = [
        Pensee::class => PenseePolicy::class,
    ];

   ...

Et pour terminer on l'utilise dans le contrôleur :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
public function destroy(Pensee $pensee)
{
    $this->authorize('delete', $pensee);

    $pensee->delete();

    return response()->json();
}

X-A-4. Routes

On a aussi besoin des routes pour accéder aux méthodes du contrôleur qu'on vient de créer et pour un peu réorganiser. Remplacez toutes les routes existantes par celles-ci :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
Auth::routes();

Route::get('/', 'PenseeController@app');

Route::resource('pensees', 'PenseeController', ['only' => [
    'index', 'store', 'destroy',
]]);

Vous devez donc avoir toutes ces routes :

Image non disponible

Notre serveur est maintenant prêt !

X-B. Le client

On va donc passer côté client maintenant…

Commencez par générer les modules avec NPM :

 
Sélectionnez
npm install

X-B-1. Vue-resource

Par défaut, Vue.js n'est pas équipé pour gérer des requêtes HTTP. On va donc installer ce package :

Image non disponible

Alors encore une petite commande :

 
Sélectionnez
npm install vue-resource

On va déclarer ce composant dans notre fichier resources/assets/js/app.js :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
window.Vue = require('vue');

var VueResource = require('vue-resource');
Vue.use(VueResource);

Vue.http.headers.common['X-CSRF-TOKEN'] = document.head.querySelector('meta[name="csrf-token"]').content;

La dernière ligne a pour objectif de créer un « header » pour la protection CSRF. Normalement axios devrait le faire, mais pour une raison que j'ignore, ça ne fonctionne pas.

Maintenant on va pouvoir créer des requêtes HTTP vers notre serveur et recevoir des réponses : en gros, communiquer !

X-B-2. La liste des pensées

Par défaut on a un composant nommé Exemple :

Image non disponible

On va changer son nom en l'appelant par exemple App :

Image non disponible

et donc renseigner en conséquence le fichier resources/assets/js/app.js qui doit donc finalement contenir ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
require('./bootstrap');

window.Vue = require('vue');
var VueResource = require('vue-resource');
Vue.use(VueResource);

Vue.component('app', require('./components/App.vue'));

const app = new Vue({
    el: '#app'
});

On va avoir besoin d'une vue de départ :

Image non disponible

avec ce simple code pour charger le composant de Vue.js :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
@extends('layouts.app')

@section('content')
  <div id="app">
    <app></app>
  </div>
@endsection
X-B-2-a. Une liste simple

Pour le composant App.vue, on va commencer par ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
<template>
    <div class="container">
        <div v-for="pensee in pensees">
          <h4>{{ pensee.user.name }}</h4>
          <p>{{ pensee.text }}</p>
          <p>{{ pensee.created_at }}</p>
        </div>
    </div>
</template>

<script>
    export default {
      resource: null,
      data () {
        return {
          pensees: {}
        }
      },
      mounted () {
        this.resource = this.$resource('/pensees{/id}')
        this.resource.get().then((response) => {
          this.pensees = response.body
        })
      }
    }
</script>

Au niveau des data, une simple variable pensees pour contenir les pensées.

Lorsque le composant est prêt (mounted), on lance la requête GET /pensees et on met le résultat dans pensees.

Dans le template, la directive v-for se charge de générer le HTML.

Si tout se passe bien, vous devez obtenir cet aspect :

Image non disponible
X-B-2-b. On améliore l'aspect

On va un peu améliorer l'aspect obtenu. On va créer un composant Card :

Image non disponible

avec ce code :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
<template>
  <div class="card red lighten-2">
    <div class="card-content white-text">
      <span class="card-title">{{ name }}</span>
      <p>{{ text }}</p>
      <p><small>{{ date }}</small></p>
    </div>
  </div>
</template>

<script>
  export default {
    props: ['name', 'text', 'date']
  }
</script>

et on va changer ainsi le code du composant App :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
<template>
    <div class="container">
        <div v-for="pensee in pensees">
          <card :name="pensee.user.name" :text="pensee.text" :date="pensee.created_at"></card>
        </div>
    </div>
</template>

<script>
    import Card from './Card'

    export default {
      resource: null,
      data () {
        return {
          pensees: []
        }
      },
      mounted () {
        this.resource = this.$resource('/pensees{/id}')
        this.resource.get().then((response) => {
          this.pensees = response.body
        })
      },
      components: {
        Card
      }
    }
</script>

Le code est mieux organisé et l'aspect plus présentable :

Image non disponible
X-B-2-c. Suppression d'une pensée

Maintenant comment faire si un utilisateur veut supprimer une de ses pensées ? Il faudrait prévoir un bouton quelque part qui n’apparaîtrait que pour le rédacteur de la pensée, mais pour le moment, rien ne nous indique que l'utilisateur actuel est le rédacteur de certaines pensées, parce qu'on ne dispose pas de son identifiant…

On va donc modifier la méthode index du contrôleur :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
public function index(Request $request)
{
    $pensees = Pensee::with('user')->oldest()->get();

    $user = auth()->check() ? auth()->id() : 0;

    return response()->json([$pensees, $user]);
}

Ainsi, on renvoie les pensées et l'identifiant de l'utilisateur en cours (0 s'il n'y en a pas).

Voici le nouveau composant App :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
<template>
    <div class="container">
        <div v-for="pensee in pensees">
          <card :pensee="pensee" :user="user" @deletePensee="deletePensee"></card>
        </div>
    </div>
</template>

<script>
    import Card from './Card'

    export default {
      resource: null,
      data () {
        return {
          pensees: [],
          user: 0
        }
      },
      mounted () {
        this.resource = this.$resource('/pensees{/id}')
        this.resource.get().then(response => {
          this.pensees = response.body[0]
          this.user = response.body[1]
        })
      },
      components: {
        Card
      },
      methods: {
        deletePensee (id) {
          this.resource.delete({id: id}).then(response => {
            let index = _.findIndex(this.pensees, function(o) { return o.id == id; })
            this.pensees.splice(index, 1)
          })
        }
      }
    }
</script>

On a le nouveau data user pour mémoriser l'identifiant de l'utilisateur.

On envoie dans le composant Card l'objet pensee et user.

On attend un événement (deletePensee) de la part de Card. Cet événement a pour effet d'activer la méthode deletePensee qui reçoit l'identifiant de la pensée. On envoie alors la requête pour supprimer cette pensée sur le serveur, et au retour on la supprime en local.

Voici le nouveau code pour Card :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
<template>
  <div class="card red lighten-2">
    <div class="card-content white-text">      
      <span class="card-title">{{ pensee.user.name }}</span>
      <p>{{ pensee.text }}</p>
      <p><small>{{ pensee.created_at }}</small></p>  
    </div>      
    <div v-if="deletable" class="card-action">
      <a href="#" @click.prevent="deletePensee">Supprimer cette pensée</a>
    </div>
  </div>
</template>

<script>
  export default {
    props: ['pensee', 'user'],
    computed: {
      deletable () {
        return this.pensee.user_id == this.user
      }
    },
    methods: {
      deletePensee () {
        this.$emit('deletePensee', this.pensee.id)
      }
    }
  }
</script>

On reçoit maintenant un objet global pensee et aussi user.

On fait apparaître le lien de suppression avec un computed qui teste l'utilisateur.

Pour la suppression, on envoie un événement ($emit) au parent App.

Image non disponible
X-B-2-d. Ajout d'une pensée

Il faut aussi pouvoir ajouter une pensée, et donc un formulaire pour la saisie, réservé aux utilisateurs connectés. On va utiliser une fenêtre modale pour le réaliser.

On va ajouter un élément dans le menu et l'activation de la fenêtre modale (resources/views/layouts/app.blade.php). Voici le code complet de la vue résultante :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">    
    @yield('css')
</head>
<body>
    <div id="app">

        @auth
            <ul id="dropdown1" class="dropdown-content">
                <li>
                    <a href="{{ route('logout') }}"
                        onclick="event.preventDefault();
                                 document.getElementById('logout-form').submit();">
                        Deconnexion
                    </a>

                    <form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">
                        {{ csrf_field() }}
                    </form>
                </li>
                <li>
                    <a class="modal-trigger" href="#ajout">Une pensée</a>
                </li>
            </ul>
        @endauth

        <nav>
            <div class="nav-wrapper">
                <a href="{{ url('/') }}" class="brand-logo">&nbsp;{{ config('app.name', 'Laravel') }}</a>
                <a href="#" data-activates="mobile-demo" class="button-collapse"><i class="material-icons">menu</i></a>
                @guest
                    <ul class="right hide-on-med-and-down">
                        <li><a href="{{ route('login') }}">Connexion</a></li>
                        <li><a href="{{ route('register') }}">Enregistrement</a></li>
                    </ul>
                    <ul class="side-nav" id="mobile-demo">
                        <li><a href="{{ route('login') }}">Connexion</a></li>
                        <li><a href="{{ route('register') }}">Enregistrement</a></li>
                    </ul>
                @else
                    <ul class="right hide-on-med-and-down">
                        <li><a class="dropdown-button" href="#!" data-activates="dropdown1">{{ Auth::user()->name }}<i class="material-icons right">arrow_drop_down</i></a></li>
                    </ul>
                @endguest
            </div>
        </nav>
        @yield('content')
    </div>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}"></script>
    <script>
        $(".button-collapse").sideNav()
        $(".dropdown-button").dropdown()
        $('.modal').modal()
    </script>
</body>
</html>

On ajoute le code de la fenêtre modale dans le composant App, ainsi que sa gestion (mise à jour, validation…) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
<template>
    <div class="container">
        <div v-for="pensee in pensees" :key="pensee.id">
          <card :pensee="pensee" :user="user" @deletePensee="deletePensee"></card>
        </div>
        <div id="ajout" class="modal">
            <form v-on:submit.prevent="addPensee">
                <div class="modal-content">
                    <h4>Ajout d'une pensée</h4>
                    <hr>
                    <div class="input-field col s12">
                        <textarea id="pensee" v-model="texte" class="materialize-textarea"></textarea>
                        <label for="pensee">Entrez ici votre pensée</label>
                        <p class="red-text">{{ error }}</p>
                    </div>
                </div>
                <div class="modal-footer">
                    <button class="btn waves-effect waves-light" type="submit">Envoyer
                        <i class="material-icons right">send</i>
                    </button>
                </div>
            </form>
        </div>        
    </div>
</template>

<script>
    import Card from './Card'

    export default {
      resource: null,
      data () {
        return {
          error: '',
          texte: '',
          pensees: [],
          user: 0
        }
      },
      mounted () {
        this.resource = this.$resource('/pensees{/id}')
        this.resource.get().then(response => {
          this.pensees = response.body[0]
          this.user = response.body[1]
        })
      },
      components: {
        Card
      },
      methods: {
        deletePensee (id) {
          this.resource.delete({id: id}).then(response => {
            let index = _.findIndex(this.pensees, function(o) { return o.id == id; })
            this.pensees.splice(index, 1)
          })
        },
        addPensee () {
          this.resource.save({ text: this.texte }).then(response => {
            $('#ajout').modal('close')
            this.texte = ''
            this.error = ''
            this.pensees.unshift(response.body)
          }, response => {
            this.error = response.body.errors.text[0]
          })
        }
      }
    }
</script>

et maintenant, on peut ajouter des pensées !

Image non disponible
X-B-2-e. Les dates en français

Vous avez sans doute remarqué que le format des dates est celui par défaut, lequel n'est pas très adapté au français. On pourrait changer ça au niveau de Laravel, mais on va le faire avec JavaScript.

On va utiliser la superbe librairie moment (l'équivalent de Carbon pour JavaScript) :

 
Sélectionnez
npm install moment

et on l'utilise dans le composant Card :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
<template>
  <div class="card red lighten-2">
    <div class="card-content white-text">      
      <span class="card-title">{{ pensee.user.name }}</span>
      <p>{{ pensee.text }}</p>
      <p><small>{{ date }}</small></p>  
    </div>      
    <div v-if="deletable" class="card-action">
      <a href="#" @click.prevent="deletePensee">Supprimer cette pensée</a>
    </div>
  </div>
</template>

<script>
  import moment from 'moment'
  moment.locale('fr')

  export default {
    props: ['pensee', 'user'],
    computed: {
      deletable () {
        return this.pensee.user_id == this.user
      },
      date () {
        return moment(pensee.created_at).format('D MMMM YYYY à H:mm:ss')
      }
    },
    methods: {
      deletePensee () {
        this.$emit('deletePensee', this.pensee.id)
      }
    }
  }
</script>

On importe la librairie :

 
Sélectionnez
import moment from 'moment'

On fixe la locale :

 
Sélectionnez
moment.locale('fr')

On crée un élément calculé :

 
Sélectionnez
date () {
  return moment(pensee.created_at).format('D MMMM YYYY à H:mm:ss')
}

et on l'utilise dans le template :

 
Sélectionnez
<p><small>{{ date }}</small></p>

Maintenant, on a les dates en bon français :

Image non disponible
X-B-2-f. La pagination

Si on commence à avoir beaucoup de pensées, il va nous falloir une pagination :

 
Sélectionnez
npm install vue-paginate

et voilà le code modifié en conséquence pour le composant App :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
<template>
    <div class="container">
      <paginate name="pensees" :list="pensees" :per="3">
        <li v-for="pensee in paginated('pensees')" :key="pensee.id">
          <card :pensee="pensee" :user="user" @deletePensee="deletePensee"></card>
        </li>
      </paginate>
      <paginate-links for="pensees" :classes="{'ul': 'pagination'}"></paginate-links>
      <div id="ajout" class="modal">
          <form v-on:submit.prevent="addPensee">
              <div class="modal-content">
                  <h4>Ajout d'une pensée</h4>
                  <hr>
                  <div class="input-field col s12">
                      <textarea id="pensee" v-model="texte" class="materialize-textarea"></textarea>
                      <label for="pensee">Entrez ici votre pensée</label>
                      <p class="red-text">{{ error }}</p>
                  </div>
              </div>
              <div class="modal-footer">
                  <button class="btn waves-effect waves-light" type="submit">Envoyer
                      <i class="material-icons right">send</i>
                  </button>
              </div>
          </form>
      </div>        
    </div>
</template>

<script>
    import Card from './Card'
    import VuePaginate from 'vue-paginate'

    export default {
      resource: null,
      data () {
        return {
          error: '',
          texte: '',
          pensees: [],
          paginate: ['pensees'],
          user: 0
        }
      },
      mounted () {
        this.resource = this.$resource('/pensees{/id}')
        this.resource.get().then(response => {
          this.pensees = response.body[0]
          this.user = response.body[1]
        })
      },
      components: {
        Card
      },
      methods: {
        deletePensee (id) {
          this.resource.delete({id: id}).then(response => {
            let index = _.findIndex(this.pensees, function(o) { return o.id == id; })
            this.pensees.splice(index, 1)
          })
        },
        addPensee () {
          this.resource.save({ text: this.texte }).then(response => {
            $('#ajout').modal('close')
            this.texte = ''
            this.error = ''
            this.pensees.unshift(response.body)
          }, response => {
            this.error = response.body.errors.text[0]
          })
        }
      }
    }
</script>

On a maintenant une pagination :

Image non disponible

On pourrait encore améliorer cette application, mais on en restera là…

X-C. En résumé

Laravel n'impose rien au niveau de la gestion côté client, et ce ne sont pas les solutions qui manquent. Toutefois, l'installation de Laravel prévoit par défaut une intendance pour Vue.js. On a vu dans ce chapitre que cette intendance est au point et que tout fonctionne de façon efficace. La prise en main de Vue.js est moins difficile que d'autres framework comme « Angular ».

Reste que le choix des outils de gestion côté client n'est pas évident. Souvent, JQuery est amplement suffisant lorsqu'on a juste à générer des requêtes HTTP et à manipuler un peu le DOM. À quel moment devient-il plus intéressant de passer à un framework plus complet ? La réponse n'est pas évidente parce qu’elle dépend de plusieurs facteurs parmi lesquels la maîtrise qu'on a d'un outil particulier n'est pas le moindre.

Si vous n'avez jamais utilisé Vue.js, je vous conseille de l'essayer parce qu'il est simple et puissant et que sa courbe d'apprentissage n'est pas rebutante.


précédentsommaire

Copyright © 2018 Maurice Chavelli. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.