Documentation vGrid

vGrid est une grille de données JavaScript qui tient dans un script et une feuille de style, sans dépendances. Vous lui fournissez vGrid({ … }) un conteneur et une URL ; votre serveur répartit, trie et filtre les données, puis la grille affiche le résultat.

vGrid({
    el: '#orders',
    dataSource: '/api/orders', // your endpoint
    rowsPerPage: 25,           // sent as limit=25
    columns: [
        { name: 'number', label: 'Order' },
        { name: 'total', label: 'Total' }
    ]
});

Cette page vous guide de cet appel jusqu’à une grille connectée à votre propre base de données, avec des milliers ou des millions de lignes. Découvrez-la en action dans l’ Exemple de produits: triez par prix, appliquez un filtre, puis ouvrez un panneau des ventes.

Télécharger

Deux fichiers exécutent la grille : vgrid.js et vgrid.css. En production, utilisez les deux fichiers minifiés.

FichierCe site
vgrid.min.jsTélécharger
vgrid.min.cssTélécharger
vgrid.js, lisibleTélécharger
vgrid.css, lisibleTélécharger

Vous pouvez aussi les charger depuis le CDN jsDelivr, qui distribue la dernière version du code disponible sur GitHub :

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/virgil2304/vGrid@main/dist/vgrid.min.css">
<script src="https://cdn.jsdelivr.net/gh/virgil2304/vGrid@main/dist/vgrid.min.js"></script>

Installation

Ajoutez vGrid à n’importe quelle page HTML en trois étapes.

Inclure vGrid

Chargez les deux fichiers depuis le CDN ou depuis votre propre copie (Télécharger). Le script définit une fonction globale, vGrid.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/virgil2304/vGrid@main/dist/vgrid.min.css">
<script src="https://cdn.jsdelivr.net/gh/virgil2304/vGrid@main/dist/vgrid.min.js"></script>

Ajouter un élément cible

N’importe quel élément convient : un <table> est utilisé tel quel ; tout autre élément reçoit un tableau à l’intérieur.

<div id="tasks"></div>

Initialiser la grille

Appelez vGrid une fois l’élément présent.

<script>
    document.addEventListener('DOMContentLoaded', () => {
        vGrid({
            el: '#tasks',
            columns: [
                { name: 'task', label: 'Task' },
                { name: 'owner', label: 'Owner' }
            ],
            data: [
                { task: 'Draft release notes', owner: 'Ava' },
                { task: 'Review pull requests', owner: 'Noah' }
            ]
        });
    });
</script>

Le résultat est une grille triable et filtrable, avec des numéros de ligne et une barre d’outils. Essayez-la dans l’ Exemple local: filtrez sur Status, puis triez par Owner.

Prérequis et compatibilité des navigateurs

Aucune dépendance, aucun framework et aucune étape de compilation. vGrid nécessite un navigateur compatible avec l’API Popover :

NavigateurMinimum
Chrome et Edge114
Firefox125
Safari et tous les navigateurs sur iOS / iPadOS17
Opera100
Samsung Internet23

Dans les anciens navigateurs, les lignes se chargent toujours, mais la fenêtre des paramètres, le menu des modes de filtre et les menus des sous-grilles ne s’ouvrent pas. Internet Explorer, les anciennes versions d’Edge et Opera Mini ne sont pas pris en charge.

Guide d’intégration

De zéro à une grille dont votre serveur répartit, trie et filtre les données. Commencez par les deux balises de Inclure vGrid et un conteneur :

<div id="orders"></div>

La grille appelle votre URL avec les paramètres de requête suivants :

GET /api/orders?page=2&limit=25&sort=total&dir=desc&status=paid

Votre point de terminaison filtre, trie, compte les résultats et renvoie une page :

{
    "data": [ { "number": "A-1001", "customer": "Ava", "status": "paid", "total": 120 } ],
    "total": 1834,
    "page": 2,
    "limit": 25
}

Côté serveur, dans le langage de votre choix : connectez-vous, lisez une page, convertissez chaque ligne en objet et renvoyez le tout sous la forme ci-dessus. C’est ce dont vGrid a besoin ; la connexion et la requête vous appartiennent.

<?php
$db = new PDO('mysql:host=localhost;dbname=shop', 'user', 'password');

$page = (int) ($_GET['page'] ?? 1);
$limit = (int) ($_GET['limit'] ?? 25);

$total = (int) $db->query('SELECT COUNT(*) FROM orders')->fetchColumn();
$rows = $db->prepare('SELECT * FROM orders LIMIT :limit OFFSET :offset');
$rows->bindValue(':limit', $limit, PDO::PARAM_INT);
$rows->bindValue(':offset', ($page - 1) * $limit, PDO::PARAM_INT);
$rows->execute();

$data = [];
foreach ($rows->fetchAll(PDO::FETCH_ASSOC) as $row) {
    $data[] = [                         // one object per row
        'number' => $row['number'],     // key = columns[].name
        'customer' => $row['customer'],
        'status' => $row['status'],
        'total' => (float) $row['total'],
    ];
}

header('Content-Type: application/json');
echo json_encode([                      // the shape vGrid reads
    'data' => $data,
    'total' => $total,                  // all matching rows, not this page
    'page' => $page,
    'limit' => $limit,
]);
import sqlite3
from flask import Flask, jsonify, request

app = Flask(__name__)

@app.get('/api/orders')
def orders():
    db = sqlite3.connect('shop.db')
    db.row_factory = sqlite3.Row

    page = int(request.args.get('page', 1))
    limit = int(request.args.get('limit', 25))

    total = db.execute('SELECT COUNT(*) FROM orders').fetchone()[0]
    rows = db.execute('SELECT * FROM orders LIMIT ? OFFSET ?',
                      (limit, (page - 1) * limit))

    data = []
    for row in rows:
        data.append({                   # one object per row
            'number': row['number'],    # key = columns[].name
            'customer': row['customer'],
            'status': row['status'],
            'total': row['total'],
        })

    return jsonify(                     # the shape vGrid reads
        data=data,
        total=total,                    # all matching rows, not this page
        page=page,
        limit=limit,
    )
using Microsoft.Data.SqlClient;

var app = WebApplication.Create(args);

app.MapGet("/api/orders", async (int page = 1, int limit = 25) =>
{
    await using var db = new SqlConnection(
        "Server=localhost;Database=shop;Integrated Security=true");
    await db.OpenAsync();

    var count = new SqlCommand("SELECT COUNT(*) FROM orders", db);
    var total = (int)(await count.ExecuteScalarAsync())!;

    var query = new SqlCommand("SELECT * FROM orders ORDER BY id " +
        "OFFSET @offset ROWS FETCH NEXT @limit ROWS ONLY", db);
    query.Parameters.AddWithValue("@offset", (page - 1) * limit);
    query.Parameters.AddWithValue("@limit", limit);

    var data = new List<object>();
    await using var rows = await query.ExecuteReaderAsync();
    while (await rows.ReadAsync())
    {
        data.Add(new                    // one object per row
        {
            number = rows["number"],    // key = columns[].name
            customer = rows["customer"],
            status = rows["status"],
            total = rows["total"]
        });
    }

    return Results.Json(new             // the shape vGrid reads
    {
        data,
        total,                          // all matching rows, not this page
        page,
        limit
    });
});

app.Run();
// application.properties
// spring.datasource.url=jdbc:mysql://localhost/shop
// spring.datasource.username=user
// spring.datasource.password=password

@RestController
public class OrdersController {
    private final JdbcTemplate db;

    public OrdersController(JdbcTemplate db) {
        this.db = db;
    }

    @GetMapping("/api/orders")
    public Map<String, Object> orders(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "25") int limit) {
        Integer total = db.queryForObject(
            "SELECT COUNT(*) FROM orders", Integer.class);
        List<Map<String, Object>> rows = db.queryForList(
            "SELECT * FROM orders LIMIT ? OFFSET ?", limit, (page - 1) * limit);

        List<Map<String, Object>> data = new ArrayList<>();
        for (Map<String, Object> row : rows) {
            Map<String, Object> item = new LinkedHashMap<>(); // one object per row
            item.put("number", row.get("number"));            // key = columns[].name
            item.put("customer", row.get("customer"));
            item.put("status", row.get("status"));
            item.put("total", row.get("total"));
            data.add(item);
        }

        Map<String, Object> response = new LinkedHashMap<>(); // the shape vGrid reads
        response.put("data", data);
        response.put("total", total);   // all matching rows, not this page
        response.put("page", page);
        response.put("limit", limit);
        return response;
    }
}
import express from 'express';
import mysql from 'mysql2/promise';

const db = await mysql.createConnection({
    host: 'localhost', user: 'user', password: 'password', database: 'shop'
});
const app = express();

app.get('/api/orders', async (req, res) => {
    const page = Number(req.query.page ?? 1);
    const limit = Number(req.query.limit ?? 25);

    const [[{ total }]] = await db.query('SELECT COUNT(*) AS total FROM orders');
    const [rows] = await db.query('SELECT * FROM orders LIMIT ? OFFSET ?',
        [limit, (page - 1) * limit]);

    const data = [];
    for (const row of rows) {
        data.push({                     // one object per row
            number: row.number,         // key = columns[].name
            customer: row.customer,
            status: row.status,
            total: row.total
        });
    }

    res.json({                          // the shape vGrid reads
        data,
        total,                          // all matching rows, not this page
        page,
        limit
    });
});

app.listen(3000);

Chaque filtre renseigné arrive sous forme de paramètre portant le nom de sa colonne ; le tri arrive sous forme de sort et dir; ajoutez-les à votre requête dans WHERE et ORDER BY.

Les points de terminaison publics de ce site sont décrits dans la Référence de l’API. Puis configurez la grille pour utiliser votre point de terminaison :

vGrid({
    el: '#orders',
    dataSource: '/api/orders',
    rowsPerPage: 25, // sent as limit=25
    columns: [
        { name: 'number', label: 'Order' },
        { name: 'customer', label: 'Customer' },
        { name: 'status', label: 'Status' },
        { name: 'total', label: 'Total' }
    ]
});

Vous voyez les 25 premières lignes, le message « Affichage de 1–25 sur 1834 » et un pagineur. Saisir un filtre envoie une requête après une courte pause ; observez-la dans l’onglet Réseau du navigateur. Un message à la place des lignes correspond à la réponse du serveur, par exemple « Le serveur a répondu avec l’erreur 500 » ou « La réponse ne contient pas le champ data ».

Découvrez son fonctionnement dans l’ Exemple Ajax: filtrez sur Name, puis triez par Code.

Dans une application utilisant un framework, les mêmes règles s’appliquent :

  • Le framework contrôle le conteneur ; vGrid contrôle tout ce qu’il contient. Ne laissez jamais le framework afficher ou effacer ses éléments enfants.
  • Créez la grille une fois le conteneur présent dans la page, puis appelez destroy() lorsqu’il en est retiré ; sinon, les écouteurs, observateurs et requêtes restent actifs.
  • La configuration est lue une seule fois. Un nouvel objet de configuration reconstruit la grille : gardez-la donc stable (useMemo, computed) et utilisez l’ API d’instance (reload(), setPage(), sort()) pour les changements courants.
  • Importez la feuille de style une seule fois, globalement. Le CSS limité à un composant (Vue scoped, les modules CSS et l’encapsulation Angular) n’atteint pas les éléments de la grille.
  • React et Vue sont facultatifs ; installez uniquement celui dont votre adaptateur a besoin.

Installer avec npm

vGrid n’est pas encore publié sur le registre npm ; npm l’installe depuis GitHub. Ajoutez #<commit> pour figer un commit.

npm install github:virgil2304/vGrid
ImportationContenu fourni
vgridLe vGrid fonction, sous forme de module ES et CommonJS
vgrid/style.cssLa feuille de style
vgrid/reactLe composant React VGRID
vgrid/vueLe composant Vue vGrid
vgrid/browservGrid, également défini comme globalThis.vGrid pour le code qui attend la variable globale
vgrid/dist/*Les fichiers de Télécharger

Avec un outil de bundling :

import { vGrid } from 'vgrid';
import 'vgrid/style.css';

const grid = vGrid({
    el: '#orders',
    dataSource: '/api/orders',
    rowsPerPage: 25,
    columns: [
        { name: 'number', label: 'Order' },
        { name: 'total', label: 'Total' }
    ]
});

// when the container leaves the page; vGrid() returns null on a bad config
grid?.destroy();

Avec CommonJS (Jest et d’autres outils basés sur require) : const { vGrid } = require('vgrid');. Tout outil de bundling qui lit package.json exports est compatible : Vite, webpack 5, Rollup, esbuild et Parcel 2.

Montage et identification

L’emplacement de la grille, sa légende et le nom qui la distingue des autres grilles de la page.

OptionValeurs acceptéesPar défautEffet
elsélecteur ou ElementobligatoireLe conteneur. Un <table> est utilisé tel quel ; le contenu de tout autre élément est remplacé par un nouveau tableau. Si l’élément est introuvable, la grille s’arrête (Dépannage).
captionchaîne HTMLaucunUne ligne en haut du tableau, à côté des boutons de la barre d’outils. Insérée au format HTML.
namespacechaîne de caractèreselde l’élément idAjoute <namespace>-<part> à côté de chaque classe vgrid-<part> , et ajoute <namespace>-row-<id> aux lignes qui possèdent un champ id . Sert aussi de nom de fichier de secours, <namespace>-<date>, si votre serveur n’en envoie pas, ainsi que le titre à l’impression.
autoDestroytrue | falsefalseDétruit la grille au prochain défilement ou redimensionnement de la fenêtre après le retrait de son conteneur. À utiliser si une page retire des grilles sans appeler destroy().

Deux grilles sur une page :

vGrid({
    el: '#orders',
    caption: 'Orders',
    dataSource: '/api/orders',
    rowsPerPage: 25,
    columns: [{ name: 'number', label: 'Order' }, { name: 'total', label: 'Total' }]
});

vGrid({
    el: document.querySelector('#returns'),
    caption: '<strong>Returns</strong>', // HTML
    namespace: 'returns-grid',               // instead of the id "returns"
    autoDestroy: true,                        // this panel can be removed
    dataSource: '/api/returns',
    rowsPerPage: 25,
    columns: [{ name: 'number', label: 'Return' }]
});

Les lignes de la seconde grille portent la classe returns-grid-row-<id>, et ses téléchargements utilisent le nom de secours returns-grid-<date> si votre serveur n’en envoie pas. Ciblez une grille avec son conteneur ou un enregistrement avec la classe de sa ligne :

#orders .vgrid-caption { /* the Orders grid's caption only */ }
.returns-grid-row-42 { /* the return with id 42 */ }

Consultez la légende et l’espace de noms dans l’ Exemple local: sa ligne de légende porte les classes vgrid-caption local-grid-caption.

Données

Les lignes proviennent d’un tableau dans la page (data) ou de votre serveur (dataSource). Si dataSource est défini, data , est ignoré.

Données locales

OptionValeurs acceptéesPar défautEffet
datatableau d’objets ligne[]Lignes conservées dans le navigateur ; la grille les trie, les filtre et les répartit elle-même en pages.
const grid = vGrid({
    el: '#tasks',
    data: tasks, // [{ task: 'Draft release notes', owner: 'Ava' }, …]
    rowsPerPage: 10,
    columns: [{ name: 'task', label: 'Task' }, { name: 'owner', label: 'Owner' }]
});

grid.reload(newTasks); // new rows, back to page 1

Toutes les lignes résident dans la page : les données locales conviennent donc aux petits ensembles, tandis que les grands ensembles doivent être traités par le serveur. Essayez dans l’ Exemple local.

Données distantes

Le navigateur conserve une page de lignes ; chaque tri, filtre ou changement de page envoie une requête à votre serveur.

OptionValeurs acceptéesPar défautEffet
dataSourceURLaucunConfigure la grille pour utiliser des données distantes. La chaîne de requête de l’URL est envoyée à chaque requête ; en cas de conflit, les paramètres de la grille prévalent.
method'GET' | 'POST''GET'GET envoie les paramètres dans la chaîne de requête ; POST les envoie dans le corps au format JSON.
headersobjet{}En-têtes supplémentaires envoyés avec chaque requête, comme un jeton d’authentification. Ils sont aussi transmis aux panneaux des sous-grilles.
vGrid({
    el: '#orders',
    dataSource: '/api/orders?region=eu', // region=eu goes with every request
    headers: { Authorization: 'Bearer ' + token },
    rowsPerPage: 25,
    columns: [{ name: 'number', label: 'Order' }, { name: 'total', label: 'Total' }]
});

Pour envoyer les paramètres dans le corps au format JSON :

vGrid({
    el: '#orders',
    dataSource: '/api/orders',
    method: 'POST', // body: {"page":1,"limit":25}
    rowsPerPage: 25,
    columns: [{ name: 'number', label: 'Order' }, { name: 'total', label: 'Total' }]
});

Consultez la grille distante dans l’ Exemple Ajax: ouvrez l’onglet Réseau du navigateur, puis triez les données ou changez de page.

La requête

Chaque chargement et chaque changement de tri, de filtre ou de page envoie les paramètres suivants : dans la chaîne de requête pour GET, dans le corps JSON pour POST.

ParamètreEnvoyé lorsqueExemple
pagetoujourspage=2
limitune taille de page est définielimit=25
sort, dirune colonne est triée ; avec un tri secondaire (Maj+activation d’un en-tête), les deux paramètres sont des listes séparées par des virgules et classées par prioritésort=total&dir=desc
sort=status,total&dir=asc,desc
columnscertaines colonnes sont masquées ; énumère les colonnes visiblescolumns=number,total
un nom de colonneson filtre contient une valeurstatus=paid
une clé de mode de filtreun mode de filtre est choisi ; une plage envoie chaque borne renseignée sous sa propre cléfrom_date=2026-01-01
un externalFilters cléle champ de saisie de la page contient une valeurregion=eu
downloadun téléchargement serveurdownload=true
langtoujours ; la langue du lecteur, vide si aucune n’est détectée (Langue)lang=de-AT
GET /api/orders?page=2&limit=25&sort=total&dir=desc&columns=number,total&status=paid&lang=en
POST /api/orders
{ "page": 2, "limit": 25, "sort": "total", "dir": "desc", "columns": "number,total", "status": "paid", "lang": "en" }

Les filtres vides sont omis. Après la saisie, la grille attend 300 ms ; une nouvelle requête annule celle qui est encore en cours.

La réponse

{
    "data": [ { "number": "A-1026", "total": 120 } ],
    "total": 1834,
    "page": 2,
    "limit": 25
}
ChampObligatoireEffet
dataouiLes lignes, indexées par columns[].name. Toute réponse autre qu’un tableau affiche une erreur à la place des lignes.
totalnon ; vaut par défaut data.lengthNombre de lignes correspondant aux filtres, toutes pages confondues. Sert à afficher « Affichage de X–Y sur Z » et le nombre de pages.
pagenon ; vaut par défaut la page demandéePage affichée. Envoyez cette valeur pour corriger une page qui n’existe plus.
limitnonTaille de page. Sans cette valeur, il n’y a ni pagineur ni ligne « Affichage ».

Consultez une réponse réelle dans l’ Exemple Ajax: dans l’onglet Réseau, ouvrez la requête vers /api/continents.

Requêtes, sécurité et noms réservés

Sur une page avec un csrf-token balise meta, chaque requête vers la même origine l’envoie comme X-CSRF-TOKEN en-tête : lignes, téléchargements et panneaux de sous-grille. Un jeton défini dans headers prévaut ; les requêtes vers d’autres origines ne le reçoivent jamais.

<meta name="csrf-token" content="…">

Ces noms servent à la pagination et au tri. Aucune colonne, externalFilters clé ou clé de mode de filtre ne peut donc les utiliser, quelle que soit la casse : page, limit, sort, dir, offset, cursor, perpage, pagesize, sortby, sortorder, columns.

{ name: 'sort', label: 'Sort order' }       // stops the grid
{ name: 'sort_order', label: 'Sort order' } // works

Une colonne ou un filtre externe portant un nom réservé arrête la grille : vGrid() renvoie null et la console indique lequel. Toute clé de mode de filtre réservée est ignorée. Consultez Dépannage.

Réponses lentes, vides ou incorrectes

Pendant une requête, les lignes s’estompent immédiatement ; après 200 ms, un indicateur « Chargement… » apparaît. Une réponse vide data tableau, affiche « Aucun enregistrement à afficher. »

Si une requête échoue, les lignes restent affichées et l’indicateur présente la raison, également annoncée aux lecteurs d’écran :

CauseMessage
Statut autre que 2xxLe serveur a répondu avec le statut <status>.
Le corps n’est pas au format JSONLa réponse n’est pas un JSON valide.
Le corps est un tableau ou nullLa réponse n’est pas un objet contenant un tableau data.
Non dataLa réponse ne contient pas le champ « data ».
data n’est pas un tableauLe champ « data » n’est pas un tableau.

La prochaine requête réussie efface le message. L’erreur est également transmise à onReady comme { error } et dans la console comme vGrid fetch error:. Personnalisez l’indicateur et la ligne vide :

.vgrid-loading-badge { /* the Loading… badge */ }
.vgrid-loading-badge.vgrid-loading-error { /* the badge showing an error */ }
.vgrid-empty td { /* the "No records to show." row */ }

Observez l’indicateur dans l’ Exemple Ajax: ralentissez la connexion dans les outils réseau du navigateur, puis changez de page.

Totaux du serveur

Affiche dans les éléments de la page des valeurs calculées par le serveur sur l’ensemble filtré, comme le chiffre d’affaires total. Grilles distantes uniquement.

OptionValeurs acceptéesPar défautEffet
externalSummaryobjet avec les clés selector ou Element{}Après chaque chargement, le texte de chaque élément prend la valeur summary portant la même clé. Si une clé manque dans summary , l’élément est vidé ; une réponse sans summary les laisse inchangés.
<p>Revenue: <span id="revenue"></span> from <span id="order-count"></span> orders</p>
vGrid({
    el: '#orders',
    dataSource: '/api/orders',
    rowsPerPage: 25,
    externalSummary: { revenue: '#revenue', count: '#order-count' },
    columns: [{ name: 'number', label: 'Order' }, { name: 'total', label: 'Total' }]
});

Votre serveur ajoute un summary tableau à la réponse :

{
    "data": [ { "number": "A-1001", "total": 120 } ],
    "total": 1834,
    "page": 1,
    "limit": 25,
    "summary": [
        { "key": "revenue", "value": "$48,210.00" },
        { "key": "count", "value": "1834" }
    ]
}

Si l’élément n’est pas présent dans la page, une erreur est enregistrée et il est ignoré.

Langue

Chaque requête d’une grille distante indique au serveur la langue du lecteur afin qu’il puisse répondre dans cette langue : valeurs traduites, dates et nombres locaux, noms dans la bonne écriture. La grille l’envoie comme lang, systématiquement à chaque requête.

OptionValeurs acceptéesPar défautEffet
localeune balise de langue, telle que 'en', 'de-AT' ou 'pt-BR'présent dans la pageLa langue que la grille transmet au serveur sous la forme lang.
locale: 'de-AT',

Origine de la langue

La grille utilise le premier de ces éléments qui contient une balise de langue valide :

#Code sourceExemple
1locale dans les options de la grillevGrid({ locale: 'de-AT' })
2Le plus proche lang attribut : sur l’élément de la grille ou l’un de ses conteneurs, jusqu’à <html><section lang="es">, <html lang="de-AT">
3Les langues du navigateur du lecteur, dans l’ordre défini par celui-cifr-FR
4Aucune de ces optionslang=, envoyé vide

Les balises sont envoyées sous leur forme standard : pt-br est envoyé comme pt-BR. Un locale qui n’est pas une balise de langue déclenche une erreur ; la grille consulte alors la page et le navigateur. La langue est lue une seule fois, à la création de la grille ; modifier l’ lang ultérieur ne le modifie pas.

Comme l’élément le plus proche lang prévaut sur <html lang>, une même page peut contenir des grilles dans plusieurs langues :

<html lang="en">
  …
  <div id="orders"></div>                  <!-- sends lang=en -->
  <div id="bestellungen" lang="de"></div>  <!-- sends lang=de -->

Ce que reçoit le serveur

RequêteEmplacement lang est
Lignes, GETchaîne de requête : /api/orders?page=1&lang=de-AT
Lignes, POSTcorps JSON : { "page": 1, "lang": "de-AT" }
Téléchargement serveurcomme pour les lignes
panneaux HTML et textechaîne de requête, quel que soit le method: /api/order-notes?id=42&lang=de-AT
Panneaux avec grilles imbriquéeschaîne de requête ou le corps de la requête, comme pour les lignes ; une grille imbriquée utilise toujours la langue de sa grille parente

La grille lang remplace toute autre valeur : un lang déjà défini dans dataSource ou dans un panneau, ainsi que la dataSource, et la propre ?lang= lorsque inheritQueryString est présent. Pour la même raison, ne nommez pas une colonne ou un externalFilters clé lang: sa valeur de filtre serait remplacée.

Lisez-le côté serveur comme tout autre paramètre et utilisez votre langue par défaut s’il est vide ou indique une langue que vous ne proposez pas :

$lang = in_array($request->input('lang'), ['en', 'de', 'fr'], true) ? $request->input('lang') : 'en';

Les grilles locales, avec data et sans dataSource, aucune requête n’est effectuée et aucune donnée n’est envoyée. Les boutons et messages propres à la grille sont en anglais.

Voir dans l’ Exemple de produits: la page est <html lang="en">, donc, dans l’onglet Réseau, chaque requête vers /api/products, ainsi que chaque panneau ouvert, transmet lang=en.

Colonnes

columns est un tableau contenant un objet par colonne, dans l’ordre d’affichage. Chaque name est une clé de vos objets ligne.

vGrid({
    el: '#orders',
    dataSource: '/api/orders',
    rowsPerPage: 25,
    columns: [
        { name: 'number', label: 'Order', width: 120 },
        { name: 'status', label: 'Status', type: 'enum', options: { paid: 'Paid', due: 'Due' } },
        { name: 'customer', label: 'Customer', type: 'link' }, // href from row.link
        { name: 'notes', label: 'Notes', type: 'html', sort: false, filter: false },
        { name: 'internal_ref', label: 'Ref', active: false }  // hidden at start
    ]
});

Identité et affichage

CléValeurs acceptéesPar défautEffet
namechaîne de caractèresobligatoireClé de la ligne affichée dans cette colonne ; elle sert également à trier et à filtrer. Noms réservés arrêtent la grille.
labelchaîne de caractèresnameTexte de l’en-tête, espace réservé du filtre, liste Paramètres, liste de tri externe, CSV et titre d’impression.
type'html' | 'enum' | 'link'texte bruthtml: la valeur est insérée en HTML ; le tri, le filtrage et le CSV utilisent son texte. enum: affiche options[value]. link: un lien vers l’adresse indiquée dans le champ href si sa valeur est un / path ; http: ou https: address ; sinon, du texte brut.
hrefnom du champ de ligne'link'Champ de ligne contenant l’adresse pour type: 'link', afin qu’une ligne puisse avoir plusieurs colonnes de lien.
optionsobjet avec les valeurs value et textaucunLa recherche pour type: 'enum'. Le tri et le filtrage locaux utilisent le texte affiché.
render(value, row) => text | Node | undefinedaucunDétermine ce que la cellule affiche. Le texte est inséré comme tel et un nœud DOM est inséré tel quel ; undefined revient à l’affichage normal de cette ligne. Le tri et le filtrage locaux utilisent la valeur brute ; le CSV et l’impression utilisent le texte affiché.
widthnumber, '120', '120px', ou tout autre <th width> valeurautomatiqueLes valeurs en pixels définissent la largeur initiale ; d’autres valeurs (telles que '20%') dimensionne la colonne jusqu’à la première mise en page.
activetrue | falsetruefalse masque la colonne au démarrage ; Paramètres peut l’afficher. Au moins une colonne doit rester visible. Les paramètres enregistrés prévalent.
isRowKeytrue | falsefalseLe numéro de ligne la cellule affiche la valeur de cette colonne. Une seule colonne au maximum ; deux arrêtent la grille.

Tri et filtrage par colonne

CléValeurs acceptéesPar défautEffet
sorttrue | falsetruefalse rend l’en-tête non cliquable et exclut la colonne de la liste de tri externe.
filtertrue | falsetruefalse laisse sa cellule de filtre vide.
filterType'select'champ de texteUne liste déroulante créée à partir de filterOptions.
filterOptionschaîne de caractères "value:Text;value:Text"''Options de la liste déroulante. Un élément sans : utilise la même valeur et le même texte ; une valeur vide (":All") signifie qu’aucun filtre n’est appliqué et active le bouton ×.
filterCleartrue | falsetruefalse supprime le bouton × de ce filtre.
filterModesobjetaucunRequêtes serveur exactes pour ce filtre ; voir Modes de filtre.
{ name: 'status', label: 'Status', filterType: 'select', filterOptions: ':All;paid:Paid;due:Due' }

Les en-têtes se trouvent dans tr.vgrid-header, et chaque contrôle de filtre porte vgrid-filter-<name>; toutes les classes sont répertoriées dans Noms de classes des éléments.

.vgrid-header th { /* every column heading */ }
.vgrid-filter-status { /* the Status filter */ }

Consultez-les dans l’ Exemple de produits: Price propose plusieurs modes de filtre ; ouvrez Paramètres et affichez Condition pour voir un filtre déroulant.

Numéros de ligne

Une première colonne qui numérote les lignes.

OptionValeurs acceptéesPar défautEffet
rowNumberstrue | falsetrueAffiche la colonne de numérotation.
rowNumbersType'sequential' | nom du champ'sequential'sequential compte les lignes sur toutes les pages : la page 2 sur 25 commence à la ligne 26. Un nom de champ affiche plutôt la valeur de ce champ.
rowNumbersType: 'id', // shows row.id

Une colonne avec isRowKey: true remplace ces deux valeurs. L’impression comporte toujours une colonne de numéros selon ces paramètres. La cellule numérique est la première de chaque ligne, sauf si une bascule de sous-grille la précède :

.vgrid-row > td:first-child { /* the row numbers */ }

Le Exemple Ajax des numéros continus entre les pages ; l’option Exemple de produits les désactive.

Tri

Cliquez sur un en-tête, ou sélectionnez-le et appuyez sur Entrée ou Espace pour trier par ordre croissant ; recommencez pour l’ordre décroissant. L’en-tête affiche ▲ ou ▼. Maintenez Maj en activant un autre en-tête pour ajouter un tri secondaire ; chaque en-tête trié indique son rang. Chaque tri ramène à la page 1. Une grille distante envoie sort et dir, sous forme de listes séparées par des virgules s’il y en a plusieurs, et votre serveur effectue le tri ; une grille locale compare les nombres si les deux valeurs sont numériques, sinon elle compare le texte affiché.

OptionValeurs acceptéesPar défautEffet
sortBy{ column, order }, ou un tableau de ces objetsaucunTri initial. column est un nom de colonne ; order est 'asc' (par défaut) ou 'desc'. Un tableau définit un tri principal et ses critères de départage, dans l’ordre.
externalSort{ column, direction }, chacun étant un sélecteur ou Element{}Les éléments de votre page <select> qui pilotent le tri. La grille renseigne column avec « Trier par… » et chaque colonne visible triable, ainsi qu’un direction avec Croissant et Décroissant. Les deux suivent les clics sur les en-têtes.
<select id="sort-column"></select>
<select id="sort-direction"></select>
sortBy: { column: 'total', order: 'desc' },
externalSort: { column: '#sort-column', direction: '#sort-direction' },
sortBy: [{ column: 'status' }, { column: 'total', order: 'desc' }], // status, then total within each status

Si un contrôle est absent de la page, une erreur est enregistrée. Les contrôles de tri externe affichent le premier tri, et sort() remplace tous les tris par celui que vous fournissez. L’en-tête trié affiche aria-sort:

.vgrid-header th[aria-sort="ascending"],
.vgrid-header th[aria-sort="descending"] { /* the sorted heading */ }

Essayez dans l’ Exemple Ajax: cliquez sur Code, puis cliquez à nouveau.

Filtrage

Trois façons de réduire le nombre de lignes : la ligne de filtres sous les en-têtes, les champs de votre page et les modes de filtre pour des requêtes serveur précises.

Ligne de filtres

Une zone par colonne. Une grille distante envoie chaque zone renseignée comme paramètre après une pause de 300 ms. Une grille locale conserve les lignes dont le texte affiché contient le texte saisi, sans tenir compte de la casse ; une liste déroulante compare exactement la valeur ou le libellé de l’option.

OptionValeurs acceptéesPar défautEffet
filterRowtrue | falsetrueAffiche la ligne de filtres.
filterCleartrue | falsetrueUn bouton × dans chaque filtre renseigné ; par colonne, avec columns[].filterClear. Échap efface également un filtre textuel.
filterRow: false, // no filter boxes

Le bouton Effacer les filtres (Actions de la barre d’outils) les efface tous.

.vgrid-filter { /* the filter row */ }
.vgrid-filter-clear { /* the × buttons */ }

Essayez dans l’ Exemple local: saisissez du texte dans Task, puis appuyez sur Échap.

Filtres externes

Les champs de saisie de votre page, envoyés avec chaque requête sous la forme name=value lorsqu’ils ont une valeur. Grilles distantes uniquement.

OptionValeurs acceptéesPar défautEffet
externalFiltersobjet avec name : sélecteur ou Element{}La grille se recharge à chaque changement de change event. Effacer les filtres les rétablit à leurs valeurs initiales.
<select id="region">
    <option value="">All regions</option>
    <option value="eu">Europe</option>
</select>
<input type="date" id="from">
externalFilters: { region: '#region', from_date: '#from' }, // region=eu&from_date=2026-01-01

Un champ textuel déclenche change avec Entrée ou lorsqu’il perd le focus. Les noms suivent les règles des noms réservés règle ; si un champ est absent de la page, une erreur est enregistrée et il est ignoré. Les champs et leurs styles vous appartiennent.

Consultez la Exemple de produits: Categories, Brand et Have Sales sont des filtres externes.

Modes de filtre

Un bouton de mode dans un filtre textuel modifie le paramètre envoyé, afin que votre serveur exécute des requêtes précises (égal à, commence par, entre) plutôt qu’une recherche « contient ». Grilles distantes et filtres textuels uniquement.

{
    name: 'price',
    label: 'Price',
    filterModes: {
        price_equals: { label: 'Equals', symbol: '=' },
        price_above: 'Higher than',
        range: { keys: ['price_from', 'price_to'], label: 'Between', symbol: '↔' }
    }
}

Saisir 25 dans Égal à envoie price_equals=25; Entre affiche les champs « de » et « à » et envoie chaque borne renseignée sous sa propre clé.

CléValeurs acceptéesPar défautEffet
filterModes.<param>libellé, ou { label, symbol, value }aucunUn mode qui envoie <param>.
filterModes.<param>.labeltexte, chaîne HTML ou Elementle nom du paramètreTexte du menu et infobulle du bouton.
filterModes.<param>.symbolchaîne de caractèresaucunSymbole du bouton et du menu ; sans cette valeur, le bouton affiche la première lettre du libellé.
filterModes.<param>.valuenon-empty text or numberaucunMakes it a one-click mode that sends this value; see One-click modes.
filterModes.range{ keys, label, symbol }aucunDeux champs, « de » et « à ».
filterModes.range.keysdeux noms de paramètres différentsobligatoires pour rangeEnvoyés pour « de » et « à ».
filterModes.range.labeltexte, chaîne HTML ou Elementles clés, from – toTexte du menu et infobulle du bouton.
filterModes.range.symbolchaîne de caractèresaucunComme ci-dessus.

Le mode « Contient » (≈), qui envoie le nom de la colonne, apparaît en premier, sauf si une clé correspond à ce nom. Le bouton n’apparaît qu’avec au moins deux modes. Changer de mode conserve le texte saisi et recharge les données si le filtre était renseigné ; Effacer les filtres rétablit le premier mode de chaque filtre.

One-click modes

A mode with a value needs no typing: choosing it reloads the grid at once and sends <param>=<value>. Use it for questions a text box can't ask, such as rows with no date.

{
    name: 'due_date',
    label: 'Due',
    filterModes: {
        due_date_empty: { label: 'No date', symbol: '∅', value: '1' },
        due_date_set: { label: 'Has a date', symbol: '✓', value: '1' }
    }
}

Choosing No date sends due_date_empty=1; any text typed in the filter is dropped. The filter box then shows "No date" and can't be typed in.

  • Click the box, or press Enter, Space or Down arrow in it, to open the mode menu and pick another mode.
  • Clear filters, the × button, or Escape in the box returns the filter to its first mode and reloads. With filterClear: false there is no × and Escape does nothing.

Your server decides what the parameter means. For "no date" on a column that can hold NULL or an empty string, match both:

WHERE due_date IS NULL OR due_date = ''

Ignorés avec une erreur dans la console : les modes sans dataSource, dans un filtre déroulant, avec une valeur vide ou une clé réservée key, a range without two different keys, or a value that is empty or set on a range (Dépannage).

.vgrid-filter-mode { /* the mode button */ }
.vgrid-filter-mode-menu { /* the menu */ }
.vgrid-filter-mode-item { /* one menu entry */ }
.vgrid-filter-mode-symbol { /* the symbol inside an entry */ }
.vgrid-filter-fixed { /* the read-only box of a one-click mode */ }

Essayez dans l’ Exemple de produits: cliquez sur le bouton de mode dans le filtre Price et choisissez Between.

Pagination

Pour les grands volumes de données, définissez toujours rowsPerPage: sans cette valeur, il n’y a pas de pagination et toutes les lignes sont demandées au serveur.

Taille de page

OptionValeurs acceptéesPar défautEffet
rowsPerPagenombre positif0, sans pagination ; 10 avec externalPagination ou externalRowsPerPageLignes par page, envoyées comme limit.
rowsPerPageOptionstableau de nombres positifsautomatiqueOptions de « Afficher N lignes » ; rowsPerPage est toujours ajouté. Automatique : 5 et 10 jusqu’à 10 lignes ; 10, 20 et 50 jusqu’à 50 ; sinon 20, 40, 50 et 100, calculés à partir des données locales ou de chaque réponse distante total. Nécessite rowsPerPage.
rowsPerPage: 25,                      // limit=25
rowsPerPageOptions: [25, 50, 100, 500],

Barres de pagination

Avec rowsPerPage configuré, une barre apparaît au-dessus et au-dessous du tableau : « Affichage de 26–50 sur 1834 », le pagineur (« ‹ 1 2 3 … › ») et « Afficher N lignes ». Sur une grille étroite, la barre s’empile et le pagineur affiche moins de numéros.

OptionValeurs acceptéesPar défautEffet
showPaginationControlstrue | falsetrueValeur par défaut pour les deux options suivantes.
showPaginationtrue | falseshowPaginationControlsLe nombre et la pagination.
showRowsPerPagetrue | falseshowPaginationControls"Show N rows".
showRowsPerPage: false, // keep the pager, drop the page-size choice
.vgrid-pagination-bar { /* each bar */ }
.vgrid-pagination-bar[data-vgrid-stacked] { /* a bar stacked on a narrow grid */ }
.vgrid-count { /* Showing X–Y of Z */ }
.vgrid-pager button[aria-current="page"] { /* the current page */ }
.vgrid-rows-per-page { /* Show N rows */ }

Voir les barres dans l’ Exemple Ajax.

Pagination externe

Place le compteur, le pagineur et le choix de taille de page dans vos propres éléments.

OptionValeurs acceptéesPar défautEffet
externalPaginationsélecteur, élément, tableau ou NodeListaucunLe contenu de chaque conteneur est remplacé par le compteur et le pagineur. Un sélecteur cible chaque élément correspondant.
externalRowsPerPagesélecteur, élément, tableau ou NodeListaucunVotre <select> éléments définissant la taille de page, synchronisés entre eux et avec la grille ; une taille manquante est ajoutée aux options.
<div class="pager-top"></div>
<select id="page-size"><option>25</option><option>50</option></select>
rowsPerPage: 25,
showPaginationControls: false,      // no built-in bars
externalPagination: '.pager-top',
externalRowsPerPage: '#page-size',

Si un élément est absent de la page, une erreur est enregistrée. Voir Exemple de produits: les pagineurs au-dessus et au-dessous de la grille sont externes ; modifiez « Afficher » dans l’un ou l’autre.

Apparence

Lignes, taille du texte, ombrage et mouvement. Les couleurs proviennent de votre page ; voir Styles et noms de classes.

OptionValeurs acceptéesPar défautEffet
borders'all' | 'horizontal' | 'rows' | 'inner' | 'none''horizontal'all: un cadre et toutes les lignes. horizontal: un cadre et des lignes entre les rangées. rows: lignes au-dessus, entre et au-dessous des lignes, sans cadre. inner: uniquement des lignes entre les rangées. none: aucune ligne.
size'smallest' | 'small' | 'medium' | 'large' | 'larger' | 'largest''medium'Taille initiale du texte, de 0,75 à 1,5 fois celle de la page. Les boutons A− et A+ parcourent les tailles et mémorisent le choix dans ce navigateur.
stripedtrue | falsetrueColore une rangée sur deux.
hovertrue | falsetrueMet en évidence la rangée sous le pointeur.
rowClassrow => stringaucunClasses ajoutées à chaque ligne selon ses données ; une valeur vide n’en ajoute aucune.
easingmillisecondes160Durée des animations des panneaux, menus et déplacements de colonnes ; 0 désactive les animations.
borders: 'all',
size: 'small',
striped: false,
easing: 0,

Une valeur inconnue génère une erreur et la valeur par défaut est utilisée. Chaque option définit un hook sur .vgrid-wrapper (Hooks définis par les options):

.vgrid-wrapper[data-vgrid-borders="all"] { /* grids with every line */ }
.vgrid-wrapper[data-vgrid-size="small"] { /* grids at size small */ }

Consultez la Exemple de produits, défini sur borders: 'horizontal' et size: 'small' ; essayez A− et A+ dans sa barre d’outils.

Redimensionnement et réorganisation des colonnes

Redimensionnement

Faites glisser la ligne entre deux en-têtes ou deux champs de filtre pour redimensionner. Les colonnes à droite cèdent ou récupèrent l’espace ; aucune ne fait moins de 40 px. Si les colonnes de droite n’ont plus de place, le tableau s’élargit. Cette fonction est toujours active et ne possède pas d’option. Le pointeur devient un curseur de redimensionnement au-dessus d’une ligne.

Lorsque les colonnes ne tiennent pas dans la largeur disponible, la grille défile horizontalement au lieu de réduire une colonne sous 40 px ; la zone de défilement peut recevoir le focus et se parcourir avec les flèches.

Sans souris : sélectionnez un en-tête et appuyez sur Alt+Flèche droite pour l’élargir ou Alt+Flèche gauche pour le réduire de 10 px ; vous pouvez aussi utiliser les boutons − et + à côté de chaque colonne dans Paramètres.

Réorganisation

Maintenez un en-tête, puis faites-le glisser à son nouvel emplacement ; un marqueur indique sa position. Si vous déplacez le pointeur avant la fin du délai, le glissement est annulé afin qu’un clic normal continue de trier.

OptionValeurs acceptéesPar défautEffet
reorderColumnstrue | falsetruePermet de déplacer les colonnes. Échap annule le glissement.
reorderDelaymillisecondes350Durée de maintien avant le début du glissement.
reorderDelay: 600, // a longer hold, for touch screens

Sans souris, les boutons ↑ et ↓ à côté de chaque colonne dans Paramètres la déplacent d’un rang. Le nouvel ordre est conservé jusqu’au rechargement de la page ; Paramètres → Enregistrer le mémorise. Il faut au moins deux colonnes visibles.

.vgrid-column-ghost { /* the heading being dragged */ }
.vgrid-column-marker { /* the drop line */ }
[data-vgrid-drag-source] { /* the column's cells during the drag */ }
[data-vgrid-dropped] { /* the column's cells just after the drop */ }

Essayez les deux dans la Exemple Ajax: faites glisser la ligne entre Code et Name, puis maintenez Name et déplacez-le vers la gauche.

Actions de la barre d’outils

Un groupe de boutons, placé par défaut à droite de la ligne de légende : Effacer les filtres ✕, Télécharger ⤓, Imprimer ⤒, Actualiser ↻, Paramètres ⚙ et A− / A+ pour la taille du texte.

Activation des fonctionnalités

OptionValeurs acceptéesPar défautEffet
settingstrue | falsetrueLe fenêtre des paramètres, ainsi que Effacer les filtres et Actualiser.
downloadtrue | false | 'server' | 'view'false'server': votre serveur envoie tous les résultats filtrés dans un fichier. 'view': un CSV généré dans le navigateur. true: server avec un dataSource, sinon view; 'server' sans dataSource utilise à la place view.
printtrue | falsetrueImprime les rangées affichées sous forme de tableau simple.
externalSettingssélecteur ou ElementaucunAncien nom de actions.element.
download: 'server',
print: false,

Un téléchargement côté serveur répète la requête actuelle (filtres, tri, colonnes visibles, page et limite) avec download=true, et enregistre le fichier reçu. Ignorez page et limit pour envoyer l’ensemble des résultats, dans le format de votre choix ; nommez le fichier avec Content-Disposition:

HTTP/1.1 200 OK
Content-Type: text/csv
Content-Disposition: attachment; filename="orders.csv"

Sans nom de fichier, la grille utilise <namespace>-<date> et une extension tirée de Content-Type. Le bouton est désactivé pendant le chargement du fichier ; en cas d’échec, la grille affiche l’erreur comme pour toute réponse incorrecte.

Un CSV généré par le navigateur ('view') utilise les libellés des colonnes comme en-têtes et le texte affiché de chaque cellule. Une grille locale exporte toutes les lignes filtrées ; une grille distante exporte la page affichée. L’impression porte toujours sur la page affichée.

Le groupe de boutons

actions accepte true (la rangée de titre), false (aucun bouton), une chaîne de position ou un objet :

CléValeurs acceptéesPar défautEffet
position'caption' | 'bottom' | 'none' | 'external''caption'bottom: une rangée sous le tableau. external nécessite element ; sans cela, les boutons restent dans le titre.
elementsélecteur ou ElementaucunConteneur de vos boutons ; son contenu est remplacé. S’il est défini, il prévaut sur position.
ordertableau de noms d’actions['clear', 'download', 'print', 'refresh', 'settings', 'textSize']Les actions indiquées d’abord, puis les autres dans l’ordre par défaut.
clearvaleur de l’actionsuit settingsClear filters ✕.
downloadvaleur de l’action, 'server' ou 'view'suit downloadTélécharger ⤓ ; remplace la valeur de niveau supérieur download.
printvaleur de l’actionsuit printImprimer ⤒.
refreshvaleur de l’actionsuit settingsActualiser ↻ : recharge les lignes distantes ou redessine les lignes locales.
settingsvaleur de l’actionsuit settingsParamètres ⚙.
textSizetrue | false | objettrueA− et A+.
actions: {
    element: '#toolbar',          // your container
    order: ['refresh', 'download'],
    download: 'server',
    print: false
},

Une clé inconnue ou un nom d’action non reconnu génère une erreur dans la console.

Valeurs des actions

Chaque action accepte true, false, une chaîne (son symbole) ou un objet :

CléValeurs acceptéesPar défautEffet
activetrue | falsetrue lorsqu’un objet est fournifalse masque le bouton.
symbolchaîne de caractères✕ ⤓ ⤒ ↻ ⚙Le texte du bouton.
titlechaîne de caractères« Effacer les filtres », « Télécharger », « Imprimer », « Actualiser » et « Paramètres »L’infobulle.
htmlchaîne HTML ou élémentaucunLe contenu du bouton, inséré en HTML ; est prioritaire sur symbol.
classNamechaîne de caractèresaucunClasses du bouton.
mode'server' | 'view''server' avec un dataSource, sinon 'view'download uniquement.
decrease, increasechaîne de caractèresA−, A+textSize uniquement : les textes des boutons.
decreaseTitle, increaseTitlechaîne de caractères"Smaller text", "Larger text"textSize uniquement : les infobulles.

textSize accepte active et className également.

actions: {
    refresh: { title: 'Reload orders', className: 'btn btn-sm btn-outline-secondary' },
    clear: '⌫',                         // a symbol
    textSize: { decrease: 'a', increase: 'A' }
},

Fenêtre des paramètres et choix mémorisés

Paramètres affiche les colonnes avec une case à cocher chacune. Appliquer conserve le choix jusqu’au rechargement de la page ; Enregistrer le mémorise aussi dans ce navigateur, avec l’ordre des colonnes. Au moins une colonne doit rester cochée. Les choix enregistrés prévalent sur columns[].active, et les colonnes masquées sont envoyées au serveur sous forme de columns.

À côté de chaque colonne, ↑ et ↓ la déplacent d’un rang, et − et + modifient sa largeur de 10 px ; le changement est immédiat et conservé jusqu’au rechargement de la page.

Les choix se trouvent dans localStorage dans vgrid:<el>:<dataSource>:columns, et la taille du texte dans …:textSize; <el> est le el sélecteur ou l’identifiant de l’élément. Modifiez el ou dataSource et les choix précédents ne s’appliquent plus. Pour les oublier :

localStorage.removeItem('vgrid:#orders:/api/orders:columns');
.vgrid-actions { /* the button group */ }
.vgrid-settings { /* the popup */ }
.vgrid-settings-actions { /* Apply and Save */ }
.vgrid-settings-close { /* the × in the popup */ }

Consultez la Exemple de produits: ses boutons sont dans la barre d’outils de la page. Ouvrez Paramètres, cochez Category, cliquez sur Enregistrer, puis rechargez la page.

Sous-grilles : panneaux de détail par ligne

Chaque sous-grille ajoute une colonne de bascule. Ouvrir la bascule d’une ligne charge son panneau depuis votre serveur : une requête par ligne ouverte, les données détaillées ne sont donc récupérées que lorsqu’elles sont consultées.

vGrid({
    el: '#orders',
    dataSource: '/api/orders',
    rowsPerPage: 25,
    columns: [{ name: 'number', label: 'Order' }, { name: 'total', label: 'Total' }],
    subgrid: {
        panels: [
            {
                name: 'items', label: 'Items', id: 'id', type: 'grid',
                dataSource: '/api/order-items',
                columns: [{ name: 'sku', label: 'SKU' }, { name: 'qty', label: 'Qty' }]
            },
            { name: 'notes', label: 'Notes', id: 'id', type: 'html', dataSource: '/api/order-notes' }
        ]
    }
});

Pour la rangée avec id 42, Items demande /api/order-items?id=42 avec les paramètres de pagination habituels et attend le format de réponse habituel réponse; Notes demande /api/order-notes?id=42 et insère la réponse en HTML.

Si un seul panneau est disponible, la bascule (+ / -) l’ouvre directement ; s’il y en a plusieurs, ⋮ ouvre un menu avec ces panneaux et Masquer. Une ligne n’affiche qu’un panneau à la fois : en ouvrir un autre remplace le précédent. Les panneaux de plus de 400 px défilent.

Groupe de sous-grilles

subgrid est un objet ou un tableau d’objets ; chacun ajoute sa propre colonne de bascule.

CléValeurs acceptéesPar défautEffet
panelstableau d’objets de panneauobligatoirePanneaux proposés par cette bascule. Tout groupe sans panneau valide est ignoré.
position'start' | 'end' | numéro de colonne'start'Emplacement de la colonne de bascule ; les cellules sont comptées de gauche à droite, à partir de 1.
singletrue | falsefalsetrue maintient un seul panneau ouvert dans toute la grille.
opentrue | nom du panneauaucunL’option qui reçoit d’abord le focus dans le menu (true: la première). Elle n’ouvre rien à elle seule.
elchaîne HTML+ / -, ⋮ pour un menuVotre propre balisage pour la bascule ; son premier élément est utilisé et devient un bouton accessible au clavier.
method'GET' | 'POST''GET'La valeur par défaut pour chaque panneau.
headersobjetde la grille headersLa valeur par défaut pour chaque panneau.
rowsPerPagenombre positif10La valeur par défaut pour chaque panneau de grille.
externalFiltersobjet avec name : sélecteur ou ElementaucunLa valeur par défaut pour chaque panneau.
subgrid: [
    { position: 'start', panels: [/* … */] },
    { position: 'end', single: true, el: '<button type="button">Details</button>', panels: [/* … */] }
],

Panneaux

CléValeurs acceptéesPar défautEffet
namechaîne de caractèresobligatoireL’identité du panneau ; utilisée par open.
labelchaîne de caractèresnameLe texte du menu, l’infobulle du bouton et les messages.
idnom du champ de ligneobligatoireChamp de la ligne dont la valeur est envoyée. Les lignes sans valeur n’affichent pas de bascule pour ce panneau.
dataSourceURLobligatoireDemandé sous forme de dataSource?id=<value>.
idInPathtrue | falsefalseRequêtes dataSource/<value> à la place.
type'grid' | 'html'texte brutgrid: une grille imbriquée. html: la réponse est insérée en HTML. Si cette option est omise, la réponse est affichée en texte.
captionchaîne HTML | falseaucunUn titre au-dessus du contenu ; le bouton × de fermeture est toujours présent.
method'GET' | 'POST'du groupe ; sinon, 'GET'
headersobjetdu groupe ; sinon, de la grille
externalFiltersobjet avec name : sélecteur ou Elementdu groupeLes champs de saisie de votre page, ajoutés à la requête du panneau à son ouverture.

Un panneau sans name, id ou dataSource est ignoré et une erreur est inscrite dans la console. Pendant le chargement, un panneau affiche « Chargement… » ; une réponse vide affiche « Rien à afficher pour Notes. » ; un échec affiche « Impossible de charger Notes : le serveur a répondu avec l’erreur 500. »

Panneaux avec grilles imbriquées

A type: 'grid' le panneau est une grille distante à l’URL du panneau : son serveur reçoit id plus page, limit, sort, dir et filtres. Ces clés s’appliquent uniquement aux panneaux de grille :

CléPar défaut
columns[], avec chaque clé de colonne
rowsPerPagedu groupe ; sinon, 10
rowNumbers, rowNumbersType, borders, striped, hover, easing, reorderColumns, reorderDelayla valeur de la grille parente
size'medium', sans héritage

Les grilles imbriquées n’ont ni paramètres ni barre d’outils, et partagent la namespace.

Héritage de la chaîne de requête

OptionValeurs acceptéesPar défautEffet
inheritQueryStringtrue | falsefalseAjoute la chaîne de requête de la page à chaque requête de panneau ; un paramètre déjà présent dans l’URL du panneau prévaut. Les requêtes de la grille principale restent inchangées.
inheritQueryString: true, // on /orders?tenant=7, panels request /api/order-items?tenant=7&id=42
.vgrid-toggle-subgrid { /* every toggle */ }
.vgrid-toggle-subgrid-2 { /* the second group's toggles */ }
.vgrid-panel-menu { /* the panel menu */ }
.vgrid-subgrid-body { /* an open panel */ }
.vgrid-subgrid-caption { /* its heading and × */ }
.vgrid-panel-error { /* a panel that failed */ }

Voir les deux types dans la Exemple de produits: le signe + au début d’une ligne ouvre Résumé, un panneau HTML demandé comme /api/products/summary/<id> (idInPath) ; la flèche ↗ à la fin ouvre Sales, une grille imbriquée.

Interactions avec les lignes

Fonctions permettant d’agir sur une ligne ou d’en copier le contenu. Elles sont toutes désactivées par défaut.

Clic et double-clic sur une ligne

OptionValeurs acceptéesPar défautEffet
onRowClickfonctionaucunAppelée avec { row, event } lorsqu’une ligne est cliquée, ou que la touche Entrée ou Espace est pressée sur une ligne sélectionnée.
onRowDblClickfonctionaucunAppelée avec { row, event } lors d’un double-clic ou avec Maj+Entrée sur une ligne sélectionnée.
onRowClick: ({ row }) => location.assign('/orders/' + row.id),

Les clics sur un bouton, un lien ou un champ de formulaire dans la ligne ne sont pas pris en compte. Lorsque cellSelection est activé, les touches agissent depuis une cellule sélectionnée plutôt que depuis la ligne.

Actions de ligne

Boutons à la fin de chaque ligne, dans une colonne intitulée Actions.

OptionValeurs acceptéesPar défautEffet
rowActionstableau d’actions ou fonction recevant la ligne et en renvoyant unfalseAjoute la colonne Actions. Une fonction détermine les boutons affichés pour chaque ligne.
Clé d’actionValeurs acceptéesPar défautEffet
labeltexte'Action'Le texte du bouton.
nametextele libelléIdentifie l’action : elle est définie comme data-vgrid-row-action sur le bouton et transmise à onClick.
onClickfonctionobligatoireAppelée avec { row, event, grid, name }; grid est le instance.
ariaLabeltextele libelléLe nom accessible, pour les libellés représentés par une icône.
disabledtrue | falsefalseAffiche le bouton comme désactivé.
rowActions: row => [
    { name: 'open', label: 'Open', onClick: ({ row }) => location.assign('/orders/' + row.id) },
    { name: 'void', label: 'Void', disabled: row.status === 'void',
      onClick: ({ row, grid }) => fetch('/api/orders/' + row.id + '/void', { method: 'POST' }).then(() => grid.reload()) },
],
.vgrid-row-actions { /* the Actions cell */ }
[data-vgrid-row-action="void"] { /* one action's button */ }

Réorganisation des lignes

Une colonne après les colonnes de données, avec des boutons ↑ et ↓ pour déplacer une ligne d’un rang.

OptionValeurs acceptéesPar défautEffet
rowReordertrue | falsefalseAjoute la colonne d’ordre des rangées.
onRowReorderfonctionaucunAppelée avec { row, from, to, rows } après un déplacement ; from et to compte à partir de 0 dans tout le jeu de données, rows est la page actuelle. Obligatoire pour une grille distante, dont le serveur conserve l’ordre.
rowReorder: true,
onRowReorder: ({ row, to }) => fetch('/api/queue/' + row.id + '/position', { method: 'PUT', body: String(to) }),

Une grille locale déplace la ligne dans ses propres données. Les boutons sont désactivés lorsqu’un tri ou un filtre est actif.

.vgrid-row-reorder { /* the Row order cell */ }
[data-vgrid-row-reorder="up"], [data-vgrid-row-reorder="down"] { /* the two buttons */ }

Sélection et copie de cellules

OptionValeurs acceptéesPar défautEffet
cellSelectiontrue | falsefalseLes cellules peuvent recevoir le focus : les flèches permettent de se déplacer, Maj avec une flèche étend la sélection, et Ctrl+C ou Commande+C copie la plage sous forme de texte séparé par des tabulations. Le collage n’est pas pris en charge.
cellSelection: true,

Cliquer sur une cellule la sélectionne ; les clics sur les boutons et les liens qu’elle contient restent inchangés. Seules les colonnes visibles sont copiées.

.vgrid [aria-selected="true"] { /* a selected cell */ }

Événements

Fonctions appelées par la grille lors d’événements. Chacune reçoit un objet ; sa valeur de retour est ignorée.

OptionAppelée lorsqueArgument
onReadyles lignes sont affichées : après chaque rendu local, chaque chargement distant ou échec de chargement distant{ total, rows }: les rangées correspondantes et celles affichées ; ou { error }
onSortle tri change : un en-tête, le tri externe ou sort(){ column, order } pour le premier tri ; également avec un tri secondaire sorts: [ { column, order } ] par ordre de priorité
onFilterun filtre change ou que Effacer les filtres est déclenché. Grilles locales uniquement ; pour une grille distante, utilisez onReady{ filters: [ { column, value } ] }
onPageune page est affichée, lorsque rowsPerPage est défini{ page, rowsPerPage, total }
onRowClick, onRowDblClickune ligne est cliquée ou double-cliquée, ou que Entrée, Espace ou Maj+Entrée est pressée sur une ligne sélectionnée. Voir Clic et double-clic sur une ligne{ row, event }
onRowReorderle bouton ↑ ou ↓ d’une rangée la déplace. Voir Réorganisation des lignes{ row, from, to, rows }
vGrid({
    el: '#orders',
    dataSource: '/api/orders',
    rowsPerPage: 25,
    columns: [{ name: 'number', label: 'Order' }, { name: 'total', label: 'Total' }],
    onReady: ({ total, error }) => {
        document.querySelector('#order-count').textContent = error ? 'unavailable' : total;
    },
    onPage: ({ page }) => history.replaceState(null, '', '?page=' + page)
});

API de l’instance

vGrid() renvoie un objet pour les modifications ultérieures. Conservez-le.

MembreEffet
elementLa grille <table>.
configL’objet que vous avez fourni.
reload(rows?)Revient à la page 1 : une grille distante recharge les données ; une grille locale se redessine et accepte de nouvelles lignes si vous lui passez un tableau.
setPage(n)Affiche la page n, 1 ou plus. Une grille locale s’arrête à sa dernière page ; pour une grille distante, le serveur page déterminée par la réponse.
sort(column, order = 'asc')Trie selon une colonne visible ; tout autre nom déclenche un avertissement.
destroy()Supprime les écouteurs, les requêtes, les panneaux et le balisage de la grille. Une <table> el reste vide.
const grid = vGrid({ /* … */ });

document.querySelector('#refresh').addEventListener('click', () => grid?.reload());
grid?.sort('total', 'desc').setPage(3); // reload, setPage and sort chain
grid?.destroy();                        // when the grid leaves the page

vGrid() renvoie null, avec une erreur dans la console, lorsque el ne trouve rien, une colonne ou un filtre externe utilise un nom réservé, deux colonnes définissent isRowKey, ou toutes les colonnes sont masquées. C’est pourquoi ?. ci-dessus.

Styles et noms de classes

vgrid.css gère uniquement la mise en page ; les couleurs et les polices proviennent de votre page. Modifiez l’apparence de la grille avec les hooks, variables et classes ci-dessous.

#orders {
    --vgrid-border-color: #c9d1d9;
    --vgrid-hover-color: #fff8e1;
}
#orders .vgrid-caption { /* the Orders grid's caption only */ }

Hooks définis par les options

OptionÉvénement
bordersdata-vgrid-borders="all | horizontal | rows | inner | none" sur .vgrid-wrapper
sizedata-vgrid-size="smallest | small | medium | large | larger | largest" sur .vgrid-wrapper
stripeddata-vgrid-striped sur .vgrid-wrapper ; les rangées colorées portent data-vgrid-stripe
hoverdata-vgrid-hover sur .vgrid-wrapper
reorderColumnsdata-vgrid-reorder sur .vgrid-wrapper
onRowClick, onRowDblClickdata-vgrid-clickable sur chaque tr.vgrid-row
cellSelectionaria-selected="true" sur les cellules sélectionnées
easing--vgrid-easing: <easing>ms sur .vgrid-wrapper
namespace<namespace>-<part> à côté de chaque vgrid-<part> classe

Variables CSS

Définissez-les dans votre CSS, sur le conteneur de la grille ou l’un de ses ancêtres ; ce ne sont pas vGrid({ … }) options.

VariablePar défautConcerne
--vgrid-border-color#dee2e6Lignes, cadres et bordures des fenêtres contextuelles
--vgrid-border-width1pxToutes les lignes
--vgrid-border-h--vgrid-border-widthLignes entre les rangées
--vgrid-border-v--vgrid-border-width; 0 dans horizontal, rows, innerLignes entre les colonnes
--vgrid-border-radius.25remCoins du cadre et des fenêtres contextuelles
--vgrid-font-sizedéfini par size, .75em à 1.5emTexte de la grille ; remplacez-le avec une règle plus spécifique que .vgrid-wrapper[data-vgrid-size]
--vgrid-hover-colorrgba(128, 128, 128, .18)La rangée sous le pointeur
--vgrid-stripe-colorrgba(128, 128, 128, .07)Rangées colorées
--vgrid-popup-backgroundCanvasParamètres, menus et indicateur de chargement
--vgrid-popup-shadow0 .4em 1.4em rgba(0, 0, 0, .18)Paramètres, menus et indicateur de chargement
--vgrid-drag-shadowune ombre douce à deux niveauxL’en-tête en cours de déplacement
--vgrid-drop-colorla couleur d’accentuation du système, estompéeLa brève mise en évidence de la colonne après son déplacement
--vgrid-scrollbar-colorla couleur du texte, estompéeBarres de défilement des paramètres, menus et panneaux
--vgrid-subgrid-max-height400pxHauteur à partir de laquelle un panneau défile

Noms de classes des éléments

Chaque classe ci-dessous existe également sous forme de <namespace>-<part>, à l’exception des cinq noms fixes à la fin du tableau.

ClasseÉlément
vgrid-captionLa rangée de titre
vgrid-actionsLe groupe de boutons dans la rangée de titre ou du bas
vgrid-actions-rowLa rangée du bas qui contient les boutons
vgrid-settings, vgrid-settings-close, vgrid-settings-title, vgrid-settings-list, vgrid-settings-actionsLa fenêtre Paramètres, son ×, son titre, la liste déroulante des colonnes et ses boutons Appliquer et Enregistrer
vgrid-headerLa rangée d’en-têtes
vgrid-filterLa rangée de filtres
vgrid-filter-<name>Le champ ou menu déroulant de filtre d’une colonne
vgrid-filter-clearLe bouton × d’un filtre
vgrid-filter-modedUn filtre avec modes, bouton et champs
vgrid-filter-mode, vgrid-filter-mode-<name>Le bouton de mode
vgrid-filter-mode-menu, vgrid-filter-mode-item, vgrid-filter-mode-symbolLe menu des modes, une option et son symbole
vgrid-filter-fixedThe read-only box of a one-click mode
vgrid-rowUne rangée de données ; avec un espace de noms et row.id, également <namespace>-row-<id>
vgrid-row-actions, vgrid-row-reorderLa cellule Actions d’une ligne et sa cellule d’ordre ; les boutons portent data-vgrid-row-action="<name>" et data-vgrid-row-reorder="up | down"
vgrid-emptyLa rangée "No records to show."
vgrid-loading-spaceEspace pour l’indicateur de chargement en l’absence de rangées
vgrid-pagination, vgrid-pagination-barUne rangée de pagination et sa barre
vgrid-count, vgrid-pager, vgrid-pager-ellipsis, vgrid-rows-per-page« Affichage de X–Y sur Z », le pagineur, son … et « Afficher N lignes »
vgrid-toggle-columnLe <col> d’une colonne de bouton de sous-grille
vgrid-toggle-subgrid, vgrid-toggle-subgrid-<n>Un bouton ; n compte les groupes à partir de 1
vgrid-panel-menu, vgrid-panel-menu-<n>, vgrid-panel-menu-itemLe menu du panneau et ses options
vgrid-subgrid-cell, vgrid-subgrid-slide, vgrid-subgrid-clip, vgrid-subgrid-bodyUn panneau ouvert, de l’extérieur vers l’intérieur
vgrid-subgrid-caption, vgrid-subgrid-title, vgrid-subgrid-closeLa barre de titre d’un panneau, son texte et son ×
vgrid-panel-loading, vgrid-panel-empty, vgrid-panel-error, vgrid-panel-textLes messages d’un panneau et une réponse en texte brut
vgrid-column-ghost, vgrid-column-markerL’en-tête déplacé et la ligne de dépôt
vgridLe <table> ; fixe
vgrid-wrapperL’élément autour du tableau ; fixe
vgrid-loading-badge, vgrid-loading-errorL’indicateur de chargement et celui de l’erreur ; noms fixes
vgrid-spinner, vgrid-loading-textL’animation et le texte de l’indicateur ; fixes

Clavier et accessibilité

Fonctions utilisables sans souris et annonces destinées aux technologies d’assistance.

  • Menus (modes de filtre, panneaux de sous-grille) : les flèches haut et bas déplacent la sélection, Début et Fin vont au début ou à la fin, Échap ferme le menu ; le menu des modes de filtre rend le focus à son bouton.
  • Boutons de sous-grille : Entrée ou Espace ; le contenu personnalisé subgrid.el devient accessible au focus avec role="button".
  • Filtres : Échap efface un filtre textuel. Déplacement de colonne : Échap annule l’action.
  • Tri : Entrée ou Espace sur un en-tête ; avec Maj, ajoute un tri secondaire.
  • Rangées et cellules : avec onRowClick, Entrée, Espace et Maj+Entrée sur une rangée ; avec cellSelection; les flèches permettent de passer d’une cellule à l’autre, et Ctrl+C ou Commande+C copie la sélection.
  • Annoncé : aria-sort sur l’en-tête trié, aria-expanded sur les boutons, aria-current sur la page actuelle, le pagineur avec son libellé, les boutons d’effacement et de fermeture, ainsi que les chargements et erreurs via une région dynamique.
  • Colonnes : Alt+Flèche gauche ou Alt+Flèche droite sur un en-tête sélectionné le redimensionne ; les boutons ↑ ↓ − + dans Paramètres déplacer et redimensionner chaque colonne.
  • Si la réduction des animations est activée dans le système, les transitions de la grille sont raccourcies ; easing: 0 les désactive.
externalSort: { column: '#sort-column', direction: '#sort-direction' }, // keyboard sorting

Sécurité

Ce que la grille insère en HTML et ce qu’elle protège, pour savoir ce que votre serveur doit nettoyer.

  • Inséré en HTML, échappez donc toute donnée utilisateur qu’il contient : caption, type: 'html' cellules, type: 'html' réponses de panneau, libellés de panneau caption, subgrid.el, filterModes et libellés d’action html. Tout le reste est inséré comme texte.
  • Liens: type: 'link' crée des liens uniquement vers les chemins commençant par un seul /, ainsi qu’aux http: et https: adresses ; tout autre contenu, comme javascript: ou //other.host, s’affiche comme texte. Un nœud renvoyé par render vous appartient : son contenu est inséré tel quel.
  • CSV: les cellules commençant par =, +, @, une tabulation ou un - qui n’est pas un nombre reçoivent en préfixe ', afin que les tableurs ne les exécutent pas comme formules.
  • En-têtes: headers sont envoyés avec chaque requête de grille ou de panneau, y compris vers d’autres origines ; le Jeton CSRF est envoyé uniquement à la même origine.
{ "data": [ { "notes": "<b>Paid</b> by &lt;script&gt;" } ] }

Ci-dessus : un type: 'html' la cellule conserve votre balise de gras et affiche le texte saisi par l’utilisateur, car le serveur l’a échappé.

Dépannage

Chaque message écrit par la grille dans la console du navigateur, sa cause et sa solution. Les messages marqués interrompt signifie vGrid() renvoyé null.

MessageCause et solution
Configuration
vGrid: "el" must identify an element. interromptLe sélecteur n’a rien trouvé. Exécutez vGrid() lorsque l’élément existe. Montage
vGrid: autoDestroy must be true or false.Utilisez une valeur booléenne. Montage
vGrid: borders must be one of …, size must be one of …, striped / hover must be true or false., easing must be a duration …La valeur par défaut est utilisée à la place. Apparence
vGrid: locale must be a language tag such as "en" or "de-AT".La grille utilise plutôt la langue de la page ou du navigateur. Utilisez une balise telle que 'de' ou 'de-AT'. Langue
Données et serveur
vGrid fetch error: avec le motifUne requête a échoué ; la grille en affiche également la raison. Réponses incorrectes
vGrid: external summary target for "…" was not found.Corrigez le sélecteur. Totaux du serveur
vGrid: reload() expects an array of rows.Fournissez un tableau ou rien. API de l’instance
Colonnes
vGrid: column name(s) … are reserved for remote API controls. interromptRenommez la colonne ou le filtre externe. Noms réservés
vGrid: only one column can use isRowKey: true. interromptGardez-le sur une seule colonne. Colonnes
vGrid: render on column "…" must be a function., … must return text or a DOM node., … failed: …La cellule affiche la valeur brute à la place. Colonnes
vGrid: href on column "…" must be a row field name.row.link est utilisé. Colonnes
vGrid: rowClass must be a function., rowClass failed: …Aucune classe n’est ajoutée. Apparence
vGrid: at least one column must stay active. interromptLaissez une colonne sans active: false. Colonnes
vGrid: column "…" not found (un avertissement)sort() désigne une colonne masquée ou inconnue. API de l’instance
Tri et filtrage
vGrid: external sort column / direction control was not found.Corrigez le sélecteur. Tri
vGrid: external filter for "…" was not found.Corrigez le sélecteur ; ce filtre est ignoré. Filtres externes
vGrid: filterModes on column "…" needs a dataSource.Les modes nécessitent une grille distante. Modes de filtre
vGrid: filterModes on column "…" works with text filters only.Supprimez filterType: 'select' ou les modes. Modes de filtre
vGrid: filterModes on column "…" must be an object of parameter: label pairs.Fournissez un objet. Modes de filtre
vGrid: filterModes range on column "…" needs keys: an array of two different parameter names.Donnez range.keys deux noms différents. Modes de filtre
vGrid: filterModes on column "…" has an empty parameter name., … uses the reserved name(s) ….Ce mode est ignoré ; renommez-le. Modes de filtre
vGrid: filterModes key "…" on column "…" needs a non-empty value and cannot be a range.That mode is dropped; give value some text, or remove it from range. One-click modes
Pagination
vGrid: rowsPerPageOptions must be a non-empty array of positive numbers., … has no effect without a positive rowsPerPage.Corrigez le tableau ou définissez rowsPerPage. Taille de page
vGrid: setPage() expects a page number of 1 or greater.Fournissez un entier supérieur ou égal à 1. API de l’instance
vGrid: external pagination control was not found., external rows-per-page control was not found.Corrigez le sélecteur. Pagination externe
Actions de la barre d’outils
vGrid: actions must be true, false, a position name, or an object., actions.position must be one of …Utilisez une valeur acceptée. Le groupe de boutons
vGrid: actions.… is not a known action., actions.order has no action named …., actions.… must be true, false, a symbol, or an object.Vérifiez l’orthographe. Valeurs des actions
vGrid: actions.element was not found., external settings control was not found., actions.position 'external' needs actions.element.Corrigez ou ajoutez le conteneur ; les boutons se placent à côté de la légende. Le groupe de boutons
vGrid: download must be true, false, or one of server, view., download: 'server' needs a dataSource.Utilisez une valeur acceptée ; sans dataSource le téléchargement produit un CSV dans le navigateur. Activation des fonctionnalités
vGrid: print must be true or false.Utilisez une valeur booléenne. Activation des fonctionnalités
vGrid download error:, vGrid print error:Le téléchargement du serveur ou l’affichage avant impression a échoué ; la grille indique la raison. Activation des fonctionnalités
vGrid: reorderDelay must be a number of milliseconds, 0 or more.La valeur par défaut 350 est utilisée. Réorganisation
Interactions avec les lignes
vGrid: rowActions must be an array, a function, or false., rowActions[].name must be a string.Aucune colonne Actions, ou le nom de l’action est identique à son libellé. Actions de ligne
vGrid: rowReorder must be true or false., cellSelection must be true or false.La fonctionnalité reste désactivée. Interactions avec les lignes
Sous-grilles
vGrid: subgrid panel "…" needs an id naming the column its value comes from., … needs a dataSource.Ce panneau est ignoré ; ajoutez la clé. Panneaux
vGrid: subgrid position must be "start", "end", or the column number counted from the left.Le bouton revient au début. Groupe de sous-grilles
vGrid: subgrid open: "…" does not match any panel name.Utilisez la valeur d’un panneau pour name. Groupe de sous-grilles
vGrid: subgrid panel "…" external filter for "…" was not found.Corrigez le sélecteur. Panneaux
vGrid panel error:Une requête de panneau a échoué ; le panneau en affiche la raison. Panneaux

Les erreurs affichées dans la grille sont répertoriées dans Réponses lentes, vides ou incorrectes.

Exemples pratiques

Questions fréquentes, avec le fragment de code correspondant.

Filtrer par intervalle de dates

{
    name: 'shipped', label: 'Shipped',
    filterModes: { range: { keys: ['shipped_from', 'shipped_to'], label: 'Between', symbol: '↔' } }
}

Votre serveur lit shipped_from et shipped_to. Plus d’informations dans Modes de filtre.

Exporter tous les résultats filtrés, et pas seulement cette page

download: 'server', // your server receives download=true with the filters and sort

Lorsque download=true arrive, ignorez page et limit et renvoyez un fichier dans n’importe quel format. Plus d’informations dans Activation des fonctionnalités et La requête.

Afficher les totaux hors de la grille

externalSummary: { revenue: '#revenue' }, // response: "summary": [ { "key": "revenue", "value": "…" } ]

En savoir plus dans Totaux du serveur.

Envoyer un jeton d’authentification

headers: { Authorization: 'Bearer ' + token }, // subgrid panels get it too

En savoir plus dans Données distantes.

Piloter la grille depuis votre propre formulaire de recherche

<input type="search" id="q" placeholder="Search orders">
<select id="status"><option value="">Any status</option><option value="paid">Paid</option></select>
externalFilters: { q: '#q', status: '#status' }, // the search box sends on Enter

En savoir plus dans Filtres externes.

Afficher les rangées de détail pour chaque enregistrement

subgrid: {
    panels: [{
        name: 'items', label: 'Items', id: 'id', type: 'grid',
        dataSource: '/api/order-items', // requested as ?id=<the row's id>
        columns: [{ name: 'sku', label: 'SKU' }, { name: 'qty', label: 'Qty' }]
    }]
},

En savoir plus dans Sous-grilles.

Mémoriser les colonnes de chaque lecteur

settings: true, // the default: Settings → Save remembers columns in this browser

Les choix sont conservés par navigateur, sous la valeur de la grille el et dataSource ; conservez les deux valeurs stables. Plus d’informations dans fenêtre des paramètres.

Placer plusieurs grilles sur une page

vGrid({ el: '#orders', dataSource: '/api/orders', columns: [/* … */] });
vGrid({ el: '#returns', dataSource: '/api/returns', columns: [/* … */] });

Chaque grille tire ses classes de l’id de son conteneur ; définissez namespace pour en choisir une autre. Plus d’informations dans Montage et identification.

Options disponibles

Toutes les options vGrid({ … }) regroupe les options par fonction. Sélectionnez un nom pour consulter sa description et un exemple.

Montage

Données et serveur

Colonnes

Clés de colonne

Numéros de ligne

Tri

Filtrage

Pagination

Apparence

Réorganisation des colonnes

Actions de la barre d’outils

Sous-grilles

Interactions avec les lignes

Événements

Toutes les options, de A à Z

actions

Place et configure les boutons de la barre d’outils. Clés : position, element, order, clear, download, print, refresh, settings, textSize. Valeur par défaut : 'caption'.

actions: { position: 'bottom' },

Plus d’informations dans Groupe de boutons

active clé de colonne

Masque la colonne au démarrage lorsque false ; les paramètres permettent de l’afficher. Valeur par défaut : true.

{ name: 'ref', active: false }

Plus d’informations dans Identité et affichage

autoDestroy

Détruit la grille lorsque son conteneur quitte la page. Valeur par défaut : false.

autoDestroy: true,

Plus d’informations dans Montage et identité

borders

Choisit les lignes dessinées par la grille. Valeur par défaut : 'horizontal'.

borders: 'all',

Plus d’informations dans Apparence

caption

Ajoute une ligne de légende en haut du tableau, insérée en HTML. Valeur par défaut : aucune.

caption: 'Orders',

Plus d’informations dans Montage et identité

cellSelection

Permet de sélectionner les cellules, de se déplacer avec les flèches, d’étendre la sélection avec Maj et de la copier sous forme de texte séparé par des tabulations. Valeur par défaut : false.

cellSelection: true,

Plus d’informations dans Sélection et copie de cellules

columns

Répertorie les colonnes dans leur ordre d’affichage, avec un objet par colonne ; chaque clé possède une entrée dans Clés de colonne. Valeur par défaut : [].

columns: [{ name: 'number', label: 'Order' }],

Plus d’informations dans Colonnes

data

Fournit à la grille ses rangées dans le navigateur. Valeur par défaut : [].

data: [{ number: 'A-1001', total: 120 }],

Plus d’informations dans Données locales

dataSource

Configure une grille distante : votre serveur répartit, trie et filtre les données. Valeur par défaut : aucune.

dataSource: '/api/orders',

Plus d’informations dans Données distantes

download

Ajoute un bouton Télécharger ; le fichier est généré par le serveur ou le navigateur. Valeur par défaut : false.

download: 'server',

Plus d’informations dans Activation des fonctionnalités

easing

Définit la durée des animations de la grille, en millisecondes. Valeur par défaut : 160.

easing: 0, // no animation

Plus d’informations dans Apparence

el

Indique l’élément qui contient la grille. Valeur par défaut : obligatoire.

el: '#orders',

Plus d’informations dans Montage et identité

externalFilters

Envoie les champs de saisie de votre page avec chaque requête. Valeur par défaut : {}.

externalFilters: { region: '#region' },

Plus d’informations dans Filtres externes

externalPagination

Place le compteur et le pagineur dans vos propres éléments. Valeur par défaut : aucun.

externalPagination: '.pager',

Plus d’informations dans Pagination externe

externalRowsPerPage

Permet à vos propres éléments de <select> définir la taille de page. Valeur par défaut : aucune.

externalRowsPerPage: '#page-size',

Plus d’informations dans Pagination externe

externalSettings

Ancien nom de actions.element. Valeur par défaut : aucune.

externalSettings: '#toolbar',

Plus d’informations dans Activation des fonctionnalités

externalSort

Permet à vos propres éléments de <select> éléments de piloter le tri. Clés : column, direction. Valeur par défaut : {}.

externalSort: { column: '#sort-column', direction: '#sort-direction' },

Plus d’informations dans Tri

externalSummary

Remplit les éléments de votre page avec les totaux envoyés par le serveur. Valeur par défaut : {}.

externalSummary: { revenue: '#revenue' },

Plus d’informations dans Totaux du serveur

filter clé de colonne

Supprime le filtre de la colonne lorsque false. Valeur par défaut : true.

{ name: 'notes', filter: false }

Plus d’informations dans Tri et filtrage par colonne

filterClear

Ajoute un bouton × aux filtres remplis. Valeur par défaut : true.

filterClear: false,

Plus d’informations dans Rangée de filtres

filterClear clé de colonne

Supprime le bouton × de cette colonne lorsque false. Valeur par défaut : true.

{ name: 'status', filterClear: false }

Plus d’informations dans Tri et filtrage par colonne

filterModes clé de colonne

Ajoute un bouton de mode qui modifie le paramètre envoyé par le filtre. Clés : une par paramètre, avec label, symbol et value; range avec keys, label et symbol. Valeur par défaut : aucune.

{ name: 'price', filterModes: { price_equals: 'Equals' } }

Plus d’informations dans Modes de filtre

filterOptions clé de colonne

Liste les choix du menu déroulant sous forme de "value:Text;value:Text". Valeur par défaut : ''.

{ name: 'status', filterType: 'select', filterOptions: ':All;paid:Paid' }

Plus d’informations dans Tri et filtrage par colonne

filterRow

Affiche une ligne de champs de filtre sous les en-têtes. Valeur par défaut : true.

filterRow: false,

Plus d’informations dans Rangée de filtres

filterType clé de colonne

Transforme le filtre en liste déroulante. Valeur par défaut : champ de texte.

{ name: 'status', filterType: 'select' }

Plus d’informations dans Tri et filtrage par colonne

headers

Ajoute des en-têtes à chaque requête, y compris celles des panneaux de sous-grille. Valeur par défaut : {}.

headers: { Authorization: 'Bearer ' + token },

Plus d’informations dans Données distantes

hover

Met en évidence la rangée sous le pointeur. Valeur par défaut : true.

hover: false,

Plus d’informations dans Apparence

href clé de colonne

Indique le champ de rangée contenant l’adresse d’une type: 'link' colonne. Valeur par défaut : 'link'.

{ name: 'customer', type: 'link', href: 'customerUrl' }

Plus d’informations dans Identité et affichage

inheritQueryString

Ajoute la chaîne de requête de la page à chaque requête de panneau. Valeur par défaut : false.

inheritQueryString: true,

Plus d’informations dans Héritage de la chaîne de requête

isRowKey clé de colonne

Affiche la valeur de cette colonne dans la cellule du numéro de ligne. Valeur par défaut : false.

{ name: 'number', isRowKey: true }

Plus d’informations dans Identité et affichage

label clé de colonne

Définit l’en-tête de colonne. Valeur par défaut : name.

{ name: 'number', label: 'Order' }

Plus d’informations dans Identité et affichage

locale

Définit la langue envoyée par la grille au serveur sous la forme de lang. Valeur par défaut : l’attribut lang le plus proche dans la page, puis la langue du navigateur.

locale: 'de-AT',

Plus d’informations dans Langue

method

Envoie les requêtes sous forme de GET, ou sous forme de corps JSON avec POST. Valeur par défaut : 'GET'.

method: 'POST',

Plus d’informations dans Données distantes

name clé de colonne

Indique la clé de ligne affichée par la colonne. Valeur par défaut : obligatoire.

{ name: 'number' }

Plus d’informations dans Identité et affichage

namespace

Nomme les classes supplémentaires de la grille et ses noms de fichier de secours. Valeur par défaut : ell’identifiant.

namespace: 'orders-grid',

Plus d’informations dans Montage et identité

onFilter

Appelée lorsqu’un filtre change dans une grille locale. Valeur par défaut : aucune.

onFilter: ({ filters }) => console.log(filters),

Plus d’informations dans Événements

onPage

Appelée lorsqu’une page est affichée. Valeur par défaut : aucune.

onPage: ({ page, total }) => console.log(page, total),

Plus d’informations dans Événements

onReady

Appelée lorsque les lignes sont affichées ou qu’un chargement distant échoue. Valeur par défaut : aucune.

onReady: ({ total, error }) => console.log(total, error),

Plus d’informations dans Événements

onRowClick

Appelée avec { row, event } lorsqu’une ligne est cliquée, ou que la touche Entrée ou Espace est pressée dessus. Valeur par défaut : aucune.

onRowClick: ({ row }) => location.assign('/orders/' + row.id),

Plus d’informations dans Clic et double-clic sur une rangée

onRowDblClick

Appelée avec { row, event } lors d’un double-clic ou avec Maj+Entrée sur une ligne sélectionnée. Valeur par défaut : aucune.

onRowDblClick: ({ row }) => openEditor(row),

Plus d’informations dans Clic et double-clic sur une rangée

onRowReorder

Appelée avec { row, from, to, rows } après le déplacement d’une ligne par le bouton ↑ ou ↓ ; obligatoire pour une grille distante avec rowReorder. Valeur par défaut : aucune.

onRowReorder: ({ row, to }) => saveOrder(row.id, to),

Plus d’informations dans Réorganisation des rangées

onSort

Appelée lorsque le tri change ; avec un tri secondaire, l’objet contient également sorts. Valeur par défaut : aucune.

onSort: ({ column, order }) => console.log(column, order),

Plus d’informations dans Événements

options clé de colonne

Associe les valeurs au texte affiché pour type: 'enum'. Valeur par défaut : aucune.

{ name: 'status', type: 'enum', options: { paid: 'Paid' } }

Plus d’informations dans Identité et affichage

print

Ajoute un bouton Imprimer pour les lignes affichées. Valeur par défaut : true.

print: false,

Plus d’informations dans Activation des fonctionnalités

render clé de colonne

Renvoie le contenu de la cellule : texte, nœud DOM ou undefined pour l’affichage normal. Valeur par défaut : aucune.

{ name: 'price', render: value => '$' + Number(value).toFixed(2) }

Plus d’informations dans Identité et affichage

reorderColumns

Permet aux lecteurs de déplacer les colonnes en maintenant et en faisant glisser un en-tête. Valeur par défaut : true.

reorderColumns: false,

Plus d’informations dans Réorganisation

reorderDelay

Définit la durée pendant laquelle il faut maintenir un en-tête avant de le déplacer, en millisecondes. Valeur par défaut : 350.

reorderDelay: 600,

Plus d’informations dans Réorganisation

rowActions

Boutons à la fin de chaque rangée. Un tableau de { name, label, onClick, ariaLabel, disabled }, ou une fonction de la rangée qui en renvoie un. Valeur par défaut : false.

rowActions: [{ name: 'open', label: 'Open', onClick: ({ row }) => location.assign('/orders/' + row.id) }],

Plus d’informations dans Actions de rangée

rowReorder

Ajoute une colonne de boutons ↑ et ↓ qui déplacent une ligne d’un rang. Valeur par défaut : false.

rowReorder: true,

Plus d’informations dans Réorganisation des rangées

rowClass

Renvoie les classes à ajouter à une ligne selon ses données. Valeur par défaut : aucune.

rowClass: row => row.status === 'overdue' ? 'table-danger' : '',

Plus d’informations dans Apparence

rowNumbers

Affiche une colonne initiale de numéros de rangée. Valeur par défaut : true.

rowNumbers: false,

Plus d’informations dans Numéros de rangée

rowNumbersType

Compte les lignes ou affiche un champ de ligne dans la colonne des numéros. Valeur par défaut : 'sequential'.

rowNumbersType: 'id',

Plus d’informations dans Numéros de rangée

rowsPerPage

Définit le nombre de lignes par page ; le serveur reçoit la valeur sous la forme limit. Valeur par défaut : 0, sans pagination.

rowsPerPage: 25,

Plus d’informations dans Taille de page

rowsPerPageOptions

Définit les choix proposés par « Afficher N lignes ». Valeur par défaut : automatique.

rowsPerPageOptions: [25, 50, 100],

Plus d’informations dans Taille de page

settings

Ajoute la fenêtre Paramètres, Effacer les filtres et Actualiser. Valeur par défaut : true.

settings: false,

Plus d’informations dans Activation des fonctionnalités

showPagination

Affiche le nombre et la pagination. Valeur par défaut : showPaginationControls.

showPagination: false,

Plus d’informations dans Barres de pagination

showPaginationControls

Affiche ou masque les deux parties des barres de pagination. Valeur par défaut : true.

showPaginationControls: false,

Plus d’informations dans Barres de pagination

showRowsPerPage

Affiche "Show N rows". Valeur par défaut : showPaginationControls.

showRowsPerPage: false,

Plus d’informations dans Barres de pagination

size

Définit la taille initiale du texte. Valeur par défaut : 'medium'.

size: 'small',

Plus d’informations dans Apparence

sort clé de colonne

Désactive le tri par en-tête lorsque false. Valeur par défaut : true.

{ name: 'notes', sort: false }

Plus d’informations dans Tri et filtrage par colonne

sortBy

Trie la grille au démarrage. Clés : column, order; un tableau ajoute les critères de départage dans l’ordre. Valeur par défaut : aucun.

sortBy: { column: 'total', order: 'desc' },
sortBy: [{ column: 'status' }, { column: 'total', order: 'desc' }],

Plus d’informations dans Tri

striped

Colore une rangée sur deux. Valeur par défaut : true.

striped: false,

Plus d’informations dans Apparence

subgrid

Ajoute des panneaux de détail qui s’ouvrent par rangée. Clés : panels, position, single, open, el, method, headers, rowsPerPage, externalFilters ; les panneaux acceptent name, label, id, dataSource, idInPath, type, caption, method, headers, externalFilters, et les clés de grille s’appliquent aux panneaux de grille. Valeur par défaut : aucune.

subgrid: { panels: [{ name: 'items', id: 'id', dataSource: '/api/order-items' }] },

Plus d’informations dans Sous-grilles

type clé de colonne

Affiche la valeur en HTML, sous forme de texte recherché ou comme lien. Valeur par défaut : texte brut.

{ name: 'notes', type: 'html' }

Plus d’informations dans Identité et affichage

width clé de colonne

Définit la largeur initiale de la colonne. Valeur par défaut : automatique.

{ name: 'number', width: 120 }

Plus d’informations dans Identité et affichage