Laravel 8

Livewire Datatable

J’ai déjà évoqué plusieurs fois Livewire dans ce blog, en particulier un article d’introduction. J’ai aussi publié récemment un article concernant la Tall Stack. Même si je n’aime pas particulièrement cet outil je dois reconnaître qu’il est bien pensé et terriblement efficace. Il permet de faire de l’Ajax sans même s’en rendre compte en gérant complètement le Javascript de façon transparente.

Dans le présent article, je vous propose d’utiliser un package pour créer des Datatables avec Livewire. Il en existe plusieurs mais mon choix s’est porté sur MedicOneSystems/livewire-datatables. Vous pouvez regarder un site de démonstation en ligne pour en voir toutes les possibilités qui sont assez complètes et qui comportent tout ce qu’on peut attendre de ce type de package :

  • on récupère les données à partir d’un modèle ou d’une requête spécifique
  • on peut mettre en forme les colonnes avec des formats prédéfinis ou de façon personnalisée
  • on peut trier à partir d’une colonne même calculée
  • on peut filtrer les données…

Vous pouvez télécharger le code final de cet article ici.

Installation

Laravel

On fait une nouvelle installation de Laravel :

composer  create-project laravel/laravel datatable --prefer-dist

On crée une base de données et on informe le fichier .env :

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=datatable
DB_USERNAME=root
DB_PASSWORD=

On peut alors créer les tables :

php artisan migrate

Tailwind

Comme on va avoir besoin de Tailwind on l’installe :

npm install
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest

On crée un fichier de configuration pour Tailwind (tailwind.config.js) :

npx tailwindcss init

Dans ce fichier de configuration on va prévoir la purge des styles non utilisés sinon on aurait toute la librairie en production avec des styles qu’on n’utilise pas :

module.exports = {
  purge: [
    './resources/**/*.blade.php',
  ],
   darkMode: false, // or 'media' or 'class'
   theme: {
     extend: {},
   },
   variants: {
     extend: {},
   },
   plugins: [],
}

Ensuite dans webpack.mix.js on ajoute Tailwind :

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        require("tailwindcss"),
    ]);

Enfin dans resources/css/app.css on ajoute ces lignes :

@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';

Ouf ! On en a terminé avec Tailwind ! Pour les fainéants on peut aussi tout simplement charger toute la librairie avec un CDN pour les essais. Les fainéant plus malin peuvent aussi installer laravel/breeze qui fait tout ça automatiquement en plus d’installer l’authentification…

Des données

Pour remplir nos datatables on va avoir besoin de données. Comme on a une seule table (users), on va un peu la remplir :

php artisan tinker
User::factory()->count(60)->create()

Livewire

Maintenant on installe Livewire :

composer require livewire/livewire

Et évidemment le package pour les Datatables :

composer require mediconesystems/livewire-datatables

Et on en a terminé avec les préparatifs !

Une simple datatable

On va commencer par une simple datatable pour afficher les données de la table users. Pour ça on va créer une vue :

Avec ce simple code parce que le package comporte déjà un composant Livewire :

<!DOCTYPE html>

<html>

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>

<body>    

    <div class="container mx-auto">
        <div class="m-10">
            <livewire:datatable model="App\Models\User" />
        </div>
    </div>    

    @livewireScripts 
</body>

</html>

On n’oublie pas de générer les assets :

npm install
npm run dev (ou watch pour suivre les modifications)

On ajoute une route :

Route::view('/datatable1', 'datatable1');

Et on obtient ceci :

La pagination fonctionne, de même que le tri sur les colonnes et le nombre de lignes affichées. Ce qui est pas mal avec le peu de code qu’on a utilisé !

On peut maintenant composer tout ça à notre goût avec pas mal de propriétés disponibles. Déjà pour n’inclure que les colonnes nécessaires (on dispose également de exclude qui fait exactement l’inverse), on peut d’ailleurs choisir le titre :

include="id, name|Nom, email, created_at|Date de création"

On peut aussi mettre les dates en forme :

dates="created_at|d-m-Y"

On peut activer la recherche pour certaines colonnes :

searchable="name, email"

On peut définir l’ordre initial :

sort="id|asc"

On peut rendre les données exportables (au format Excel) :

exportable

Avec tout ça voilà où en est notre datatable :

Voilà le code utilisé :

<livewire:datatable 
    model="App\Models\User"
    include="id, name|Nom, email, created_at|Date de création"
    dates="created_at|d-m-Y"
    searchable="name, email"
    sort="id|asc"
    exportable
/>

C’est bien pratique et rapide tout ça ! Même si je tombe sur un bug pour le titre de la date qui n’est pas pris en compte si on ajoute le formatage de la date. Je n’ai pas creusé l’affaire, mais sans doute le traitement n’est pas réalisé par la même classe.

Je ne vais pas évoquer la traduction française qui devrait je pense rapidement arriver sur ce package et qui de toute façon est facile à ajouter.

On crée un composant

Si les propriétés ne suffisent pas il faut créer un composant :

php artisan livewire:datatable datatable2 --model=user

Par défaut on a ce code :

<?php

namespace App\Http\Livewire;

use App\User;
use Mediconesystems\LivewireDatatables\Http\Livewire\LivewireDatatable;

class Datatable2 extends LivewireDatatable
{
    public $model = User::class;

    public function columns()
    {
        //
    }
}

Le namespace du modèle n’est pas bon, mais c’est facile à arranger, par contre j’espérais que la génération irait plus loin…

On va compléter le code ainsi :

<?php

namespace App\Http\Livewire;

use App\Models\User;
use Mediconesystems\LivewireDatatables\{ 
    Http\Livewire\LivewireDatatable,
    Column,
    NumberColumn,
    DateColumn
};

class Datatable2 extends LivewireDatatable
{
    public $model = User::class;

    public function columns()
    {
        return [

            NumberColumn::name('id')
                ->label('ID'),  

            Column::name('name')
                ->label('Nom')
                ->searchable(),

            Column::name('email')
                ->searchable(),

            DateColumn::name('created_at')
                ->label('Date de création')

        ];
    }
}

Là on doit utiliser les classes de base pour gérer les colonnes : NumberColumn, Column, DateColumn. Il existe aussi BooleanColumn et TimeColumn.

On retrouve la datatable :

Pour le moment on n’a rien gagné à créer le composant, mais on dispose de bien plus de possibilité à présent. Par exemple on peut rendre filtrable une colonne :

Column::name('name')
    ->label('Nom')
    ->searchable()
    ->filterable(),

Il apparaît alors une zone de saisie (ou deux si c’est une colonne numérique) :

On peut réaliser beaucoup de choses comme :

  • créer une requête spécifique (avec par exemple des jointures)
  • masquer ou montrer des colonnes
  • calculer la valeur d’une colonne
  • arrondir une valeur numérique

Vous pouvez trouver toute la liste dans la documentation et surtout une série très complète d’exemples.

Les relations

On a toujours des relations dans nos données voyons comment cela est pris en charge avec le package. On va commencer par créer une nouvelle migration avec le modèle et le factory :

php artisan make:model Book -mf

Dans la migration on prévoit un titre et la clé étrangère pour les users :

public function up()
{
    Schema::create('books', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->timestamps();
        $table->foreignId('user_id')->constrained();
    });
}

On lance la migration pour créer la table (tant qu’à faire on recrée toutes les tables pour purger celle des users) :

php artisan migrate:fresh

On ajoute la relation dans User :

public function books()
{
    return $this->hasMany(Book::class);
}

Et la réciproque dans Book :

public function user()
{
    return $this->belongsTo(User::class);
}

On code le factory pour les livres :

public function definition()
{
    return [
        'title' => $this->faker->sentence(3, true),
    ];
}

On utilise encore tinker pour créer 20 users avec 3 livres chacun :

php artisan tinker
User::factory()->count(20)->hasBooks(3)->create();

On crée un nouveau composant :

php artisan livewire:datatable datatable3 --model=book

On veut la liste des livres avec pour chacun le nom du user :

<?php

namespace App\Http\Livewire;

use App\Models\Book;
use Mediconesystems\LivewireDatatables\{ 
    Http\Livewire\LivewireDatatable,
    Column,
    NumberColumn
};

class Datatable3 extends LivewireDatatable
{
    public $model = Book::class;

    public function columns()
    {
        return [

            NumberColumn::name('id')
                ->label('ID'),  

            Column::name('title')
                ->label('Titre'),
            
            Column::name('user.name')
                ->label('Auteur'),
        ];
    }
}

Conclusion

Je suis loin d’avoir épuisé toutes les possibilités de ce package qui est très séduisant. Décidément Tailwind et Livewire inspirent beaucoup de monde !

Print Friendly, PDF & Email

Laisser un commentaire