PagingTagHelper v1.0.0: Enterprise-Ready Pagination for Modern ASPM SK2NET Core (Français (French))

PagingTagHelper v1.0.0: Enterprise-Ready Pagination for Modern ASPM SK2NET Core

Friday, 07 November 2025

//

25 minute read

NOTE: COMING SOONM SK1 just putting the finishing touches to it. Suivre sur GitHub! .

Ce n’est que pour vous montrer tout je fais des progrès avec ce contrôle.

Introduction

Après des mois d'évolution et de rétroaction précieuse de la communauté (5.7kM SK1 téléchargements!), JeMSC3 suis heureux d'annoncer que la bibliothèque PagingTagHelper a atteint sa version 1.0.0. Ce n'est pas seulement une bouffée de numéros de version ♫ – elle représente une maturation complète de la bibliothèque avec des fonctionnalités qui la rendent appropriée pour les applications de production réelles ♫

Si vous ' avez suivi cette série ,, vous vous souvenez que nous avons commencé avec bare-bones paging, ajouté en-têtes triables, et extraits Contrôle de la taille des pagesVersion 1.0.0 prend tout ce que nous avons appris et ajoute des fonctionnalités essentielles de l’entreprise

  • Page d'affichage du symbole de continuité pour les bases de données NoSQL (Cosmos DBM SK1 DynamoDB, Storage des tables d'AzureMSC3
  • Localisation multi-language appuyer les langues 8 hors de la boîte
  • Modes de JavaScript souples de HTMX à zéro-JavaScript
  • Vues pures du vent de Tail sans dépendance DaisyUI
  • Préservation des paramètres de l'URL intelligent à travers toute la navigation
  • HTMX 2.0.4 mise à niveau avec compatibilité arrière

Let's plonger dans chacune de ces fonctionnalités et voir comment elles travaillent ensemble pour créer une solution vraiment souple en pagenage.

NuGet NuGet

Page d'affichage du symbole de continuité {#continuationM SK1token-paginationMSC3

La pagerie traditionnelle fonctionne bien avec les bases de données SQL où vous pouvez facilement SKIP et TAKE records. Mais que se passe-t-il lorsque vous œuvrez avec des bases de données NoSQL comme Cosmos DB, ,, DynamoDB ou Azure Table Storage? Tokens de continuation.

Comprendre le token-Pagement basé M SK1comprendre-token -Pagements basésMSC4Pages baséesMST5

Voici's comment la page d'affichage du symbole de continuité diffère de la pagerie traditionnelle

graph TD
    A[Traditional Paging] --> B[Page 1: OFFSET 0 LIMIT 10]
    A --> C[Page 2: OFFSET 10 LIMIT 10]
    A --> D[Page 3: OFFSET 20 LIMIT 10]

    E[Token-Based Paging] --> F[Page 1: No token]
    F --> G[Returns: Data + Token_A]
    G --> H[Page 2: Token_A]
    H --> I[Returns: Data + Token_B]
    I --> J[Page 3: Token_B]

    style A stroke:#0ea5e9,stroke-width:3px
    style E stroke:#ec4899,stroke-width:3px

Paging traditionnel:

  • Vous spécifiez exactement les enregistrements à extraire (OFFSETM SK1LIMIT)
  • Vous pouvez cliquer directement sur une page
  • La base de données doit parcourir tous les dossiers antérieurs

Token-Paiguillage basé:

  • La base de données retourne un token opaque représentant "où poursuivre"
  • Le format du token est une base de données - spécifique et opaque pour le client
  • La navigation vers l’avant est naturelle, la navigation à l’arrière requiert une histoire de cote

Mise en oeuvre de l'affichage continue

La nouvelle <continuation-pager> L'aide à l'étiquette fait de la mise en œuvre d'un token-page simple basée sur . Premièrement, créer un modèle qui met en oeuvre IContinuationPagingModel:

public class ProductPagingViewModel : IContinuationPagingModel
{
    public string? NextPageToken { get; set; }
    public bool HasMoreResults { get; set; }
    public int PageSize { get; set; } = 25;
    public int CurrentPage { get; set; } = 1;
    public Dictionary<int, string>? PageTokenHistory { get; set; }
    public ViewType ViewType { get; set; } = ViewType.TailwindAndDaisy;

    // Your actual data
    public List<Product> Products { get; set; } = new();
}

L'interface est minime mais puissante. Laissez's regarder ce que chaque propriété faitM SK2

  • NextPageToken: Le token pour récupérer la page suivante ( fourni par votre base de données
  • HasMoreResults: Boolean indiquant s'il y a plus de pages
  • PageSize: Articles par page
  • CurrentPage: Display-numéro de page seulement pour l'interface
  • PageTokenHistory: Carte du dictionnaire des numéros de page aux tokens pour la navigation à l'arrière
  • ViewType: Quel cadre CSS à utiliser pour la traduction

Maintenant, let's mettre en oeuvre une action de contrôleur qui simule la pagenage du Cosmos DB-style PagenationM SK2

[Route("Products")]
public async Task<IActionResult> Products(
    int currentPage = 1,
    int pageSize = 25,
    string? pageToken = null,
    string? tokenHistory = null)
{
    // Simulate fetching from Cosmos DB
    var cosmosResults = await _cosmosService.GetProductsAsync(
        pageSize: pageSize,
        continuationToken: pageToken
    );

    // Deserialize token history for backward navigation
    var history = string.IsNullOrEmpty(tokenHistory)
        ? new Dictionary<int, string>()
        : JsonSerializer.Deserialize<Dictionary<int, string>>(tokenHistory)
          ?? new Dictionary<int, string>();

    // Store current token in history
    if (!string.IsNullOrEmpty(pageToken))
    {
        history[currentPage] = pageToken;
    }

    var viewModel = new ProductPagingViewModel
    {
        CurrentPage = currentPage,
        PageSize = pageSize,
        NextPageToken = cosmosResults.ContinuationToken,
        HasMoreResults = cosmosResults.HasMoreResults,
        PageTokenHistory = history,
        Products = cosmosResults.Items
    };

    if (Request.IsHtmx())
    {
        return PartialView("_ProductList", viewModel);
    }

    return View(viewModel);
}

Cette mise en œuvre montre comment l'historique des tokens permet une navigation arrière. Sans elle, la page d'affichage continue du token ne supporterait que les boutons M SK2Suivant+" . En gardant un dictionnaire de pageMSC5àMST6marquages de tokensMSP7, nous pouvons soutenir à la fois SSK8Précédente+MST9 et "+Suivante+MSP11+la navigation+MSS12+

Voici'le flux de l’accumulation des tokens est visualisé:

sequenceDiagram
    participant User
    participant Controller
    participant Database
    participant TokenHistory

    User->>Controller: Request Page 1 (no token)
    Controller->>Database: Query with no token
    Database-->>Controller: Data + Token_A
    Controller->>TokenHistory: Store Token_A for page 1
    Controller-->>User: Display Page 1

    User->>Controller: Request Page 2 (Token_A)
    Controller->>Database: Query with Token_A
    Database-->>Controller: Data + Token_B
    Controller->>TokenHistory: Add Token_B for page 2
    Controller-->>User: Display Page 2

    User->>Controller: Request Page 1 (retrieve from history)
    Controller->>TokenHistory: Get Token for Page 1
    Controller->>Database: Query with Token_A
    Database-->>Controller: Data + Token_A
    Controller-->>User: Display Page 1

Dans votre vision Razor, l'utilisation du messageur de continuité est simple:

@model ProductPagingViewModel

<div id="product-container">
    <table class="table">
        <thead>
            <tr>
                <th>Product</th>
                <th>Company</th>
                <th>Price</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var product in Model.Products)
            {
                <tr>
                    <td>@product.Name</td>
                    <td>@product.CompanyName</td>
                    <td>[email protected]("N2")</td>
                </tr>
            }
        </tbody>
    </table>

    <continuation-pager
        model="Model"
        htmx-target="#product-container"
        show-page-number="true"
        show-pagesize="true" />
</div>

L'aide-étiquette automatique:

  • Serialise l'historique du token en paramètres de demande
  • Construit des URL de navigation avec les tokens appropriés
  • Disable "PrécédenteM SK1 lorsqu'il est sur la page 1
  • Disable "Next" lorsque HasMoreResults est fausse
  • Préserve tous les autres paramètres de la demande (searchM SK1 filters, etc .)

Historique du token pour la navigation arrière

Le génie de l’approche historique des tokens est qu’elle'est entièrement facultativeM SK1 Si vous n’avez besoin que "SuivantMSC3 navigation (roule infinieMST5 par exempleM ST6 vous pouvez ignorer complètement l’histoire des tokensM st7

<continuation-pager
    model="Model"
    enable-token-accumulation="false"
    show-page-number="false" />

Cela rend simplement un bouton "NextM SK1 sans indicateurs de page ni gestion historique.

Pour la navigation intégrale, l'historique du token est automatiquement serialisé en JSON dans la chaîne de rechercheM SK1 ici's ce qu'une URL ressemble avec l'histoire du tokens :

/Products?currentPage=3&pageSize=25&pageToken=abc123&tokenHistory=%7B%221%22%3A%22xyz789%22%2C%222%22%3A%22abc123%22%7D

L'article 5 de la Loi sur l'immigration et le statut des réfugiés tokenHistory Paramètre contenant le dictionnaire codé, rendant la navigation vers l'arrière sans fil.

Navigation de la page numérotée

L'une des améliorations les plus importantes de l'UX dans le navigateur continu est Les boutons de page numérotés. Au fur et à mesure que vous naviguez vers l’avant, le navigateur affiche les numéros de pages à cliquer pour toutes les pages visitées.

Initial page 1:    [Next →]
After next click:  [← Prev] [1] [2 active] [3 disabled] [Next →]
After next click:  [← Prev] [1] [2] [3 active] [4 disabled] [Next →]
Click page 2:      [← Prev] [1] [2 active] [3] [4 disabled] (no next - not visited yet)

Cela fournit une page UX traditionnelle tout en conservant les tokens-architecture de backend basée sur . La mise en œuvre stocke des tokens pour chaque page visitée, permettant la navigation directe vers toute page déjà consultée .

Limiter la croissance historique:

Pour empêcher l'utilisation de mémoire non liée, max-history-pages (défaultM SK1 20):

<continuation-pager
    model="Model"
    max-history-pages="50"
    show-page-number="true" />

Lorsque la limite est atteinte, les tokens de page les plus anciens sont trimés automatiquement.

Critical: Préservation des paramètres de la demande M SK1query-parameter -preservationMSC4

Il s’agit de la caractéristique la plus importante de la mise en œuvre du messageur continu.

Les tokens de continuité ne sont valides qu'avec le même contexte de demande (filtres, trisM SK2 recherches ) qui les ont généréesMSC4 Utiliser un token avec différents paramètres de demande produira des données inexactes ou échouera complètement

Le périphérique de continuation préserve automatiquement TOUS les paramètres de demande à l'exception de son propre

<!-- URL with filters -->
/Products?category=electronics&brand=acme&minPrice=100

<!-- After clicking Next -->
/Products?category=electronics&brand=acme&minPrice=100&currentPage=2&pageToken=xyz123&tokenHistory={...}

<!-- All filters preserved! Token is valid because query context matches. -->

Vous pouvez désactiver ce comportement si nécessaire:

<continuation-pager
    model="Model"
    preserve-query-parameters="false" />

Mais c'est d’une part, et de l’autre à moins que vous n’êtes'absolument sûrs que vos tokens ne dépendent pas du contexte de la demande

Pourquoi cela importe:

Exemple de DB Cosmos:

// Page 1 with filter
var query = container.GetItemQueryIterator<Product>(
    "SELECT * FROM c WHERE c.category = 'electronics'",
    continuationToken: null
);
var response = await query.ReadNextAsync();
// Returns: Products + Token_A

// Page 2 with SAME filter - Token_A is valid
var query2 = container.GetItemQueryIterator<Product>(
    "SELECT * FROM c WHERE c.category = 'electronics'",
    continuationToken: Token_A  // ✅ Works!
);

// Page 2 with DIFFERENT filter - Token_A is invalid
var query3 = container.GetItemQueryIterator<Product>(
    "SELECT * FROM c WHERE c.category = 'computers'",
    continuationToken: Token_A  // ❌ Wrong results or error!
);

La conservation automatique des paramètres du pager de poursuite' garantit que les tokens sont toujours utilisés avec leur contexte original de demande.


Soutien à la localisation {#localisation-supportM SK2

Les applications modernes servent des auditoires mondiaux, et les contrôles de pagement ont besoin pour parler à vos utilisateurs ' langueM SK2 Version 1.0.0 inclut un soutien global de localisation intégrée directement dans la bibliothèque

Élaboré-dans les langues {#élaboré

La bibliothèque fournit des traductions pour les langues 8

Code Langue
en Anglais (défault)
de Allemand (DeutschM SK2
es Espagnol (EspañolM SK2
fr Français (FrançaisM SK2
it Italique (ItalianoM SK2
pt Portuguese (PortuguêsM SK2
ja Japonais (日本語)
zh-Hans Chinois simplifiés (简体中文)

Tous les textes sont localisés, y compris:

  • Précédente/SuivanteM SK1Première/La dernière étiquette des boutons
  • Texte sommaire de la page ("Showing X to Y of Z itemsM SK1
  • Étiquettes ARIA pour l'accessibilité
  • Étiquette de la taille de la page ("Items par pageM SK1

Le système de localisation est alimenté par .resx fichiers de ressources, ce qui facilite l'ajout de vos propres langues. Tous les fichiers sont en mostlylucid.pagingtaghelper/Resources/.

Usage de la localisation {#localisation-usageM SK2

L’utilisation de la localisation est simple. Just add the language attribute:

<paging
    model="Model"
    language="de"
    show-summary="true"
    first-last-navigation="true" />

Cela rend tous les textes en allemand:

<!-- Previous button -->
<button>‹ Vorherige</button>

<!-- Summary -->
<div class="text-sm text-gray-600">
    Zeige 1 bis 10 von 256 Einträgen
</div>

<!-- Next button -->
<button>Nächste ›</button>

Pour changer le langage dynamique selon les préférences de l'utilisateur, configurez la langue dans votre contrôleur:

public async Task<IActionResult> Products(
    int page = 1,
    int pageSize = 10,
    string language = "en")
{
    var pagingModel = await GenerateModel(page, pageSize);
    ViewBag.SelectedLanguage = language;
    return View(pagingModel);
}

Ensuite, dans votre vue, créez un sélecteur de langues:

@{
    var selectedLanguage = ViewBag.SelectedLanguage as string ?? "en";
    var languages = new Dictionary<string, string>
    {
        { "en", "English" },
        { "de", "German" },
        { "es", "Spanish" },
        { "fr", "French" },
        { "it", "Italian" },
        { "pt", "Portuguese" },
        { "ja", "Japanese" },
        { "zh-Hans", "Chinese" }
    };
}

<select onchange="window.location.href='/Products?language=' + this.value">
    @foreach (var lang in languages)
    {
        <option value="@lang.Key" selected="@(lang.Key == selectedLanguage)">
            @lang.Value
        </option>
    }
</select>

<paging
    model="Model"
    language="@selectedLanguage"
    link-url="/Products" />

Vous pouvez aussi surrider des chaînes de texte individuelles tout en profitant de la localisation pour d'autres éléments:

<paging
    model="Model"
    language="ja"
    previous-page-text="戻る"
    next-page-text="次へ"
    summary-template="全{TotalItems}件中 {StartItem}~{EndItem}件を表示" />

L'article 5 de la Loi sur l'immigration et le statut des réfugiés PagingLocalizer service gère la culture-formatage spécifique automatiquement. Si vous passez un code de langue inapproprié , il revient gracieusement à l’anglais

Pour l’intégration HTMX, vous' voudrez préserver la langue à travers les demandes :

<script>
    htmx.on('htmx:configRequest', function(event) {
        if (event.detail.path.includes('/Products')) {
            event.detail.parameters.language = '@selectedLanguage';
        }
    });
</script>

Cela garantit que les mises à jour de la vue partielle HTMX maintiennent le langage sélectionné.


Modes de JavaScript {#javascript-modesM SK2

L’une des améliorations les plus importantes de v1.0.0 est l’introduction de modes JavaScript souples. use-htmx="true" ou use-htmx="false". Vous avez maintenant cinq modes distincts, chacun optimisé pour différents scénarios.

Modes disponibles {#available-modesM SK2

Voici la ventilation complète des modes de JavaScript'

graph TD
    A[JavaScript Modes] --> B[HTMX]
    A --> C[HTMXWithAlpine]
    A --> D[Alpine]
    A --> E[PlainJS]
    A --> F[NoJS]

    B --> B1[Uses HTMX for partial updates]
    B --> B2[hx-get, hx-target, hx-swap]

    C --> C1[HTMX + Alpine.js directives]
    C --> C2[Enhanced interactivity]

    D --> D1[Pure Alpine.js]
    D --> D2[x-data, @click handlers]

    E --> E1[Vanilla JavaScript]
    E --> E2[onclick handlers]

    F --> F1[Zero JavaScript]
    F --> F2[Standard anchor links & forms]

Let's voir chaque mode en action

Modèle HTMX (Default)

<paging
    model="Model"
    js-mode="HTMX"
    htmx-target="#results-container" />

Rendeurs:

<button hx-get="/Products?page=2" hx-target="#results-container" hx-swap="outerHTML">
    Next ›
</button>

Perfect pour les mises à jour dynamiques des pages sans rechargement de la page entière. Ce mode est recommandé pour les applications modernes ASP.NET CoreM SK2

2. HTMXWithAlpine Mode

<paging
    model="Model"
    js-mode="HTMXWithAlpine"
    htmx-target="#results-container" />

Rendeurs:

<button
    x-data
    hx-get="/Products?page=2"
    hx-target="#results-container"
    hx-swap="outerHTML">
    Next ›
</button>

Combine HTMX pour la navigation avec Alpine.js pour un client additionnel-interactivité des côtésM SK2 Utilisez-le lorsque vous avez besoin d'éléments de l'UI réactifs parallèlement à la page d'affichage.

3. Mode alpin

<paging
    model="Model"
    js-mode="Alpine" />

Rendeurs:

<button
    x-data
    @click="window.location.href = '/Products?page=2'">
    Next ›
</button>

Pure Alpine.js sans HTMX. Utilisable lorsque vous utilisez déjà l’AlpineM SK3js mais que vous ne voulez pas les dépendances de HT MX '

4. Mode PlainJS

<paging
    model="Model"
    js-mode="PlainJS" />

Rendeurs:

<button onclick="window.location.href = '/Products?page=2'">
    Next ›
</button>

Aucune dépendance de cadre, JavaScript vanilla seulement. Ce mode inclut également un aideur pour les changements de taille des pagesM SK2

@Html.PageSizeOnchangeSnippet()

Cela injecte le JavaScript nécessaire pour traiter les changements de taille des pages en descendant sans HTMX.

5. Mode NoJS

<paging
    model="Model"
    js-mode="NoJS" />

Rendeurs:

<!-- Navigation uses standard anchor links -->
<a href="/Products?page=2">Next ›</a>

<!-- Page size uses a form with submit button -->
<form method="get" action="/Products">
    <input type="hidden" name="page" value="1" />
    <select name="pageSize" onchange="this.form.submit()">
        <option value="10">10</option>
        <option value="25" selected>25</option>
        <option value="50">50</option>
    </select>
    <noscript>
        <button type="submit">Update</button>
    </noscript>
</form>

Zero JavaScript requis. parfait pour:

  • Exigences d'accessibilité
  • Systèmes d'amélioration progressive
  • Environnements où JavaScript est désactivé
  • SEO- pages critiques où vous voulez un crawler - navigation conviviale

La beauté de ce système est que Tous les modes préservent vos paramètres de demande existants. Que vous filteriez par catégories, soit par recherche ou par classement, la page d'affichage maintient automatiquement votre état.

Migration à partir de l'utilisation-htmx M SK1migration-deMSC3utilisation -htm xMST5

Pour la compatibilité arrière, l'ancien use-htmx attribute encore fonctionne:

<!-- Old syntax (still works) -->
<paging model="Model" use-htmx="true" />
<!-- Equivalent to js-mode="HTMX" -->

<paging model="Model" use-htmx="false" />
<!-- Equivalent to js-mode="PlainJS" -->

Cependant, Je recommande de migrer vers le nouveau js-mode attribut de clarté:

<!-- New syntax (recommended) -->
<paging model="Model" js-mode="HTMX" />
<paging model="Model" js-mode="PlainJS" />

Améliorations du type de vision {#type de vue-améliorancesM SK2

Version 1.0.0 introduit deux ajouts importants de ViewType qui traitent des scénarios réels communsM SK1world.

Vent de caoutchouc pur {#pure-tailwindM SK2

Précédemment, si vous voulez TailwindCSS styling, vous avez le TailwindAndDaisy vue qui utilise les composants DaisyUI. C'est excellent si vous'vous utilisez déjà DaisyUI~, mais que dire si vous voulez Tailwind pure sans dépendance de DaisyUI?

Inscrire ViewType.Tailwind:

<paging
    model="Model"
    view-type="Tailwind" />

Il n'est utilisé que les classes d'utilité Tailwind standard:

<div class="flex gap-2 items-center">
    <button class="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700">
        ‹ Previous
    </button>

    <div class="px-3 py-1 text-sm font-medium bg-gray-100 dark:bg-gray-700 dark:text-white rounded-md">
        Page 1
    </div>

    <button class="px-4 py-2 text-sm font-medium rounded-md bg-blue-600 text-white hover:bg-blue-700">
        Next ›
    </button>
</div>

Non btn, badge, ou join classes – juste pure Tailwind. Cela vous donne un contrôle complet sur le style sans dépendance de la bibliothèque des composantsM SK2

Comparaison:

Type de visualisation Cadre CSS CMS2 Bibliothèque des composants DMS3 Case d'utilisation DMS4
TailwindAndDaisy TailwindCSS DaisyUI Les projets qui utilisent déjà DaisyUI
Tailwind TailwindCSS
Bootstrap Bootstrap Components de l'embouchure d'un embouchère Projets de mise en place d'une embouchée
Plain CSS Embedded Aucune CMS2 Aucunes dépendances de cadres CMS3
NoJS CSS Embedded Aucune

Mode NoJS {#nojs-modeM SK2

L'article 5 de la Loi sur l'immigration et le statut des réfugiés NoJS ViewType combine 0 JavaScript avec le style CSS simple:

<paging
    model="Model"
    view-type="NoJS"
    show-pagesize="true" />

Principales différences par rapport aux autres types de vue:

  1. La navigation utilise des liens d'ancrage, sans boutonsM SK1
<a href="/Products?page=2" class="pager-button">Next ›</a>
  1. Le sélecteur de la taille des pages est un formulaire:
<form method="get" action="/Products" class="page-size-form">
    <!-- Preserves all current query parameters as hidden inputs -->
    <input type="hidden" name="search" value="laptop" />
    <input type="hidden" name="category" value="electronics" />

    <!-- Reset to page 1 when changing page size -->
    <input type="hidden" name="page" value="1" />

    <label for="pageSize">Items per page:</label>
    <select name="pageSize" onchange="this.form.submit()">
        <option value="10">10</option>
        <option value="25" selected>25</option>
        <option value="50">50</option>
    </select>

    <!-- Button visible when JavaScript is disabled -->
    <noscript>
        <button type="submit" class="page-size-button">Update</button>
    </noscript>
</form>

L'article 5 de la Loi sur l'immigration et le statut des réfugiés onchange="this.form.submit()" fournit une facilité lorsque JavaScript est disponible, mais le <noscript> le bouton garantit la pleine fonctionnalité lorsqu’il's n’est pas


Préservation des paramètres de l’URL {#url-paramètreM SK2préservationMSC3

L’un des aspects les plus frustrants de la mise en œuvre de pages est la perte de vos filtres, termes de recherche , ou ordre de classement lorsque vous naviguez entre les pagesM SK2 Version 1.0.0 résout cela avec élégance par préserver automatiquement tous les paramètres de recherche à l'exception du contrôle de pagenage' ses propres parameters.

Cette caractéristique fonctionne de façon identique à travers Les navigateurs réguliers et les navigateurs de continuité, et au-dessus Tous les modes de JavaScript et tous les types de vue.

Voici comment il fonctionne à l’interne'

string BuildQueryString(string? token, int page)
{
    var query = new Dictionary<string, string>();

    // Define continuation pager's own parameters that should be excluded from preservation
    var pagerParams = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
    {
        "pageSize", "currentPage", "pageToken", "tokenHistory"
    };

    // Add parameter prefix variants if using prefixed parameters
    if (!string.IsNullOrEmpty(Model.ParameterPrefix))
    {
        pagerParams.Add($"{Model.ParameterPrefix}_pageSize");
        pagerParams.Add($"{Model.ParameterPrefix}_currentPage");
        pagerParams.Add($"{Model.ParameterPrefix}_pageToken");
        pagerParams.Add($"{Model.ParameterPrefix}_tokenHistory");
    }

    // Preserve all existing query parameters (except pager's own) if enabled
    if (Model.PreserveQueryParameters)
    {
        foreach (var param in ViewContext.HttpContext.Request.Query)
        {
            if (!pagerParams.Contains(param.Key))
            {
                query[param.Key] = param.Value.ToString();
            }
        }
    }

    // Add continuation pager parameters (with prefix if specified)
    var pageSizeParam = Model.GetParameterName("pageSize");
    var currentPageParam = Model.GetParameterName("currentPage");
    var pageTokenParam = Model.GetParameterName("pageToken");
    var tokenHistoryParam = Model.GetParameterName("tokenHistory");

    query[pageSizeParam] = pageSize.ToString();
    query[currentPageParam] = page.ToString();

    if (!string.IsNullOrEmpty(token))
        query[pageTokenParam] = token;

    if (Model.EnableTokenAccumulation)
        query[tokenHistoryParam] = tokenHistoryJson;

    return string.Join("&", query.Select(kvp =>
        $"{Uri.EscapeDataString(kvp.Key)}={Uri.EscapeDataString(kvp.Value)}"));
}

Cette approche signifie:

Scénario 1: Recherche + Pagement

Initial URL: /Products?search=laptop&category=electronics&page=1
Click Next: /Products?search=laptop&category=electronics&page=2
Change Page Size: /Products?search=laptop&category=electronics&page=1&pageSize=50

Scénario 2: Sortage + Pagement

Initial URL: /Products?orderBy=price&descending=true&page=1
Click Page 3: /Products?orderBy=price&descending=true&page=3

Scénario 3: Pager de poursuite avec filtres

Initial URL: /Products?category=electronics&brand=acme
Click Next: /Products?category=electronics&brand=acme&currentPage=2&pageToken=abc123&tokenHistory={...}

La même préservation s’applique aux formulaires (Mode NoJS). Lorsque vous produisez le formulaire de taille de pageM SK2, la vue inclut automatiquement des intrants cachés pour tous les paramètres autres que les pages de page.

<form method="get" action="@linkUrl" class="page-size-form">
    @* Preserve all existing query parameters except pageSize and page-related ones *@
    @foreach (var param in ViewContext.HttpContext.Request.Query)
    {
        if (!new[] { "pageSize", "currentPage", "pageToken", "tokenHistory" }
            .Contains(param.Key, StringComparer.OrdinalIgnoreCase))
        {
            <input type="hidden" name="@param.Key" value="@param.Value" />
        }
    }

    @* Reset to page 1 when changing page size *@
    <input type="hidden" name="currentPage" value="1" />

    <select name="pageSize" onchange="this.form.submit()">
        <!-- options -->
    </select>
</form>

Cela fonctionne sans fil à travers Tous les modes JavaScript et tous les types de vue. Vous n'avez jamais à gérer manuellement la propagation des chaînes de demande.


Guide de migration

La mise à niveau des versions antérieures est simple-1.0 mais il y a quelques changements qui doivent être pris en considération.

Résilier les changements

1. use-htmx est répréhensible ( mais fonctionne toujoursM SK1

:

<paging model="Model" use-htmx="true" />
<paging model="Model" use-htmx="false" />

Nouveau (recommandéM SK1

<paging model="Model" js-mode="HTMX" />
<paging model="Model" js-mode="PlainJS" />

2. ViewType.TailwindAndDaisy utilise maintenant les composants DaisyUI complets

Si vous utilisez ViewType.TailwindAndDaisy et veulent de pure Tailwind sans DaisyUI:

Observations antérieures (pure TailwindM SK1

<paging model="Model" view-type="TailwindAndDaisy" />

Nouveau (pour obtenir le comportement antérieurM SK1

<paging model="Model" view-type="Tailwind" />

Continuer d'utiliser TailwindAndDaisy si vous utilisez les composantes DaisyUI'

<paging model="Model" view-type="TailwindAndDaisy" />
<!-- Uses btn, join, badge, select, etc. -->

3. HTMX a été mis à niveau pour 2.0.4

Si vous utilisez HTMX ailleurs dans votre application, veillez à ce qu'il soit compatible avec HT MX 2.0.4. La plupart des codes HTX 1.x fonctionnent sans changementM SK4 mais réexaminez les Guide de migration HTMX 2.0 pour les cases à bord.

Step-by-Step Migration

Étape 1: Mise à jour du paquet NuGet

dotnet add package mostlylucid.pagingtaghelper --version 1.0.0

Étape 2: Examiner votre code existant

Recherchez votre base de code pour use-htmx attributs:

# PowerShell
Get-ChildItem -Recurse -Include *.cshtml | Select-String "use-htmx"

# Bash/Git Bash
grep -r "use-htmx" --include="*.cshtml" .

Étape 3: Mise à jour au jsM SK1mode (recommandée)

Remplacer use-htmx avec js-mode:

- <paging model="Model" use-htmx="true" htmx-target="#results" />
+ <paging model="Model" js-mode="HTMX" htmx-target="#results" />

- <paging model="Model" use-htmx="false" />
+ <paging model="Model" js-mode="PlainJS" />

Étape 4: Examiner l'utilisation de TailwindAndDaisy

Si vous n’avez pas installé DaisyUI, mais que vous utilisez TailwindAndDaisy:

- <paging model="Model" view-type="TailwindAndDaisy" />
+ <paging model="Model" view-type="Tailwind" />

Étape 5: Essai approfondi

Suivre votre application et tester:

  • Navigation des pages
  • Changements de taille des pages
  • HTMX mises à jour partielles (si vous utilisez HT MX)
  • Filtre/conservation de la recherche
  • Réceptivité mobile

Nouvelles fonctionnalités à adopter

Une fois migrée, envisagez d’adopter ces nouvelles fonctionnalités:

Localisation:

<paging
    model="Model"
    language="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName" />

Pageur de continuité (si vous utilisez NoSQL):

<continuation-pager
    model="Model"
    htmx-target="#results-container"
    show-page-number="true" />

Mode NoJS (pour l'accessibilité):

<paging model="Model" js-mode="NoJS" />

Application de démonstration

La bibliothèque comprend une application de démonstration complète montrant toutes les fonctionnalités. Vous pouvez la lancer localement ou la visualiser sur le site de démonstration (viendra bientôtM SK1

Démarrage de la démonstration locale:

git clone https://github.com/scottgal/mostlylucid.pagingtaghelper.git
cd mostlylucid.pagingtaghelper/mostlylucid.pagingtaghelper.sample
dotnet run

Naviger vers https://localhost:5001 pour explorer:

  1. Pagement de base avec modèle - Pagage traditionnel avec SQL-page de style
  2. Intégration HTMX - Mise à jour dynamique des pages sans rechargement de la page entière
  3. Recherche avec HTMX - Recherche combinée et pagination
  4. Plaine CSS - Aucune dépendance de cadre
  5. Vent de Tail pur - TailwindCSS sans DaisyUI
  6. Aucun JavaScript - Nullité fonctionnelle intégrale-Pagement JS
  7. Modes de JavaScript - Tous les cinq modes de JS ont été démontrés sur le côté
  8. Sortir la page - Entêtes sortables avec HTMX
  9. Page Sortie Aucune HTMX - Entêtes sortables avec charge de page complète
  10. Taille de la page avec HTMX - Changements dynamiques de taille des pages
  11. Taille de la page Aucun HTMX - Taille de la page avec présentation du formulaire
  12. Pageur de la poursuite Pagenage basé sur - NoSQL-token de styleM SK2
  13. Localisation - Choseur de langue avec les langues 8

Chaque démonstration comprend:

  • Code de source opérationnel
  • Explication de la technique
  • Lien vers la mise en œuvre de GitHub
  • Contrôles interactifs pour expérimenter

Conclusion

Version 1.0.0 représente un jalon majeur pour la bibliothèque PagingTagHelper . Ce qui commençait à être une exigence de travail simple s'est transformé en une solution de production complète,M SK3de pagerie prête qui gère les pagesMSC4

  • Pagenage traditionnel de SQL avec offset/limite
  • Pagenage du token de la poursuite de NoSQL pour Cosmos DB, DynamoDB, etcM SK2
  • Localisation linguistique multi- pour les auditoires mondiaux
  • Modes de JavaScript souples de HTMX à zéro-JavaScript
  • Plusieurs cadres CSS de DaisyUI à Tailwind pure à aucun
  • Conservation intelligente des paramètres à travers toute la navigation
  • Soutien de l'accessibilité complète avec les étiquettes ARIA et la navigation de clavier

La bibliothèque a été battue-testée avec les téléchargements M SK1k+ et est prête à l’utilisation en production . Tous les tests d’unité de |106 sont passésMSC5, et l’application expérimentale complète montre des modèles réels de ­-utilisation dans le monde.

Qu’est-ce que's Suivant?

Améliorations à venir I'm en considération :

  • Soutien supplémentaire du cadre CSS (Utilité de l'interface matérielleM SK1 Bulma)
  • Plus de langues de localisation (accueillir les contributions communautaires!)
  • Server-components Blazor côté
  • Caractéristiques d'accessibilité améliorée
  • Optimisation du rendement pour les grands ensembles de données

Démarrer

Installer via NuGet:

dotnet add package mostlylucid.pagingtaghelper --version 1.0.0

Consultez la documentation:

Questions, rétroactionM SK1 ou contributions ? Ouvrir une question sur GitHub ou contacter sur Twitter @scottgal.

Pageage heureux! 🚀

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.