# Barre de filtrage : Progrès, bugs et petites victoires

<!--category-- HTMX, ASP.NET, JavaScript -->
<datetime class="hidden">2025-11-10T14:10</datetime>

## Présentation

J'ai mis en place une barre de filtre appropriée pour la liste des blogs : la langue, la portée de la date, le tri et la pagination qui reste écailleuse avec HTMX.

Il est proche maintenant—mais comme toujours, le dernier 20% est le bit épicé: dates, caches, et pourquoi cela fonctionne-t-il localement mais pas après un échange?[Si vous voulez la plongée profonde avec beaucoup de code et de diagrammes, voir:](/blog/filterbarprogressandissues)

> /blog/filterbarprogressandissues

[TOC]

## Rappelez-vous que ce site est un travail en cours, ce genre de choses va se produire lorsque vous mangez-votre-dogfood!

- TL;DR
- Nouvelle barre de filtre : Langue + Tri + Gamme de date
- Les swaps partiels HTMX permettent de garder la page rapidement; back/forward fonctionne parce que j'appuie toujours sur l'URL mise à jour`/blog/calendar-days`Les faits saillants du calendrier proviennent d'une minuscule
- critère d' évaluation
- Correction : les plages de dates sont supprimées lors du changement de langue/ordre
- Correction : calendrier non rafraîchissant après les swaps HTMX ou les changements de thème

## La mise en cache du serveur varie désormais selon toutes les touches de requête pertinentes

- Ce qui fonctionne bien
- Comportement URL-first: Toutes les interactions mettent à jour l'URL; vous pouvez créer un lien profond vers un état de filtre`LinkUrl`Pagination préserve les filtres actuels (
- est réglé sur le serveur)

```csharp
// Server: cache and vary for index
[ResponseCache(Duration = 300, VaryByHeader = "hx-request",
  VaryByQueryKeys = new[] { "page", "pageSize", nameof(startDate), nameof(endDate), nameof(language), nameof(orderBy), nameof(orderDir) },
  Location = ResponseCacheLocation.Any)]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] { "hx-request" },
  VaryByQueryKeys = new[] { nameof(page), nameof(pageSize), nameof(startDate), nameof(endDate), nameof(language), nameof(orderBy), nameof(orderDir) })]
public async Task<IActionResult> Index(int page = 1, int pageSize = 20, DateTime? startDate = null, DateTime? endDate = null,
  string language = MarkdownBaseService.EnglishLanguage, string orderBy = "date", string orderDir = "desc")
{
    var posts = await blogViewService.GetPagedPosts(page, pageSize, language: language, startDate: startDate, endDate: endDate);
    posts.LinkUrl = Url.Action("Index", "Blog", new { startDate, endDate, language, orderBy, orderDir });
    if (Request.IsHtmx()) return PartialView("_BlogSummaryList", posts);
    return View("Index", posts);
}
```

## Flatpickr range par défaut aux valeurs de requête actuelles si présent et met en évidence jours avec les messages

### Les bogues que j'ai corrigés (et les nouvelles fonctionnalités !)

Visibilité et contrôle du contenu

- **Le plus grand ajout: une bonne gestion de la visibilité post-visibilité:**Postes cachés`IsHidden`: Les messages peuvent maintenant être marqués comme cachés (
- **drapeau) et n'apparaîtra pas dans les listes**Publication programmée`ScheduledPublishDate`: Les messages peuvent avoir un
- **et n'apparaissent qu'après cette période**Postes épinglés`IsPinned`: Postes marqués d'un

```csharp
// BlogService now filters appropriately
var now = DateTimeOffset.UtcNow;
postQuery = postQuery.Where(x =>
    !x.IsHidden &&
    (x.ScheduledPublishDate == null || x.ScheduledPublishDate <= now));

// Pinned posts sorted first on page 1
if (isFirstPage)
{
    postQuery = postQuery.OrderByDescending(x => x.IsPinned)
                         .ThenByDescending(x => x.PublishedDate.DateTime);
}
```

### apparaissent toujours en premier à la page 1 (grand pour les annonces)

- **Amélioration de la portée des dates`/blog/date-range`Nouveau**critère d' évaluation
- **: Renvoie les dates min/max sur tous les messages (language-aware) afin que le sélectionneur de dates puisse définir des limites sensées**Effacer l'aide de la balise param`<clear-param>`: Ajouté

```cshtml
<clear-param name="startDate">Clear Date</clear-param>
<clear-param all="true" exclude="language">Clear All Filters</clear-param>
```

### tag helper pour effacer facilement les paramètres de la requête

- Corrections des bogues
  - Perdre la plage de dates lors du changement de langue ou de commande`new URL(window.location.href)`Correction : Commencer à partir de

```js
langSelect.addEventListener('change', async function(){
  const u = new URL(window.location.href);
  u.searchParams.set('language', langSelect.value);
  u.searchParams.set('page','1');
  const [ob,od] = (orderSelect.value||'date_desc').split('_');
  u.searchParams.set('orderBy', ob);
  u.searchParams.set('orderDir', od);
  if(input._flatpickr && input._flatpickr.selectedDates.length===2){
    const [s,e] = input._flatpickr.selectedDates;
    u.searchParams.set('startDate', s.toISOString().substring(0,10));
    u.searchParams.set('endDate',   e.toISOString().substring(0,10));
  }
  applyNavigation(u);
});
```

- et ne remplace que les paramètres changeants; si Flatpickr a une sélection, l'appliquer de nouveau.
  
  - Points saillants du calendrier non rafraîchissants après les swaps HTMX`fp.redraw()`Correction: Détruire/recréer Flatpickr sur init, puis récupérer les points forts pour le mois visible et appeler`htmx:afterSwap`.

- ; également re-run init sur
  
  - Styles de mode sombres ne s'appliquant pas au calendrier`<html class>`Correction: observer`fp.redraw()`et appeler

## quand ça change.

```mermaid
sequenceDiagram
  participant User
  participant JS as blog-index.js
  participant HT as HTMX
  participant S as Server

  User->>JS: Change language/order or pick a date range
  JS->>JS: Update URLSearchParams, pushState
  JS->>HT: htmx.ajax('GET', /blog?...)
  HT->>S: GET /blog
  S-->>HT: HTML partial (_BlogSummaryList)
  HT-->>User: Swap #content
```

## Comment les morceaux parlent

Détection de la demande de page HTMX`pagerequest`La barre de filtre utilise une fonction personnalisée

```csharp
public static bool IsPageRequest(this HttpRequest request)
{
    return request.Headers.ContainsKey("pagerequest") &&
           request.Headers["pagerequest"] == "true";
}
```

l'en-tête pour aider le serveur à distinguer les chargements de pages entières des swaps HTMX partiels:

> **Cela permet au contrôleur de retourner simplement la vue partielle pour les requêtes HTMX et les vues pleines de page pour la navigation directe.**Remarque

## : L'extension de la balise d'aide à la recherche et le paramètre de requête plus clair Alpine.js composants méritent leur propre plongée profonde – je vais les couvrir en détail dans un futur post sur la construction réutilisable composants HTMX/Alpine.

- Encore à faire
- Préréglages de date rapide (7/30 derniers jours, cette année)
- Semences locales de stockage pour la langue

Prise en charge du clavier sur le sélectionneur de portée