# Filterleiste: Fortschritt, Bugs und kleine Gewinne

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

## Einleitung

Ich habe eine richtige Filterleiste für die Blogliste zusammengestellt: Sprache, Datumsbereich, Sortierung und Pagination, die mit HTMX blitzschnell bleibt.

Es schließt sich jetzt – aber wie immer sind die letzten 20% das würzige Bit: Datteln, Caches, und warum funktioniert das lokal, aber nicht nach einem Swap?[Wenn Sie den tiefen Tauchgang mit vielen Code und Diagrammen wollen, sehen Sie:](/blog/filterbarprogressandissues)

> /blog/filterbarprogressandissues

[TOC]

## Erinnern Sie sich an diese Website ist eine Arbeit im Gange, diese Art von Zeug wird passieren, wenn Sie essen-Ihre-eigenen-Hund-Lebensmittel!

- TL;DR
- Neue Filterleiste: Sprache + Sortierung + Datumsbereich
- HTMX-Teilswaps halten die Seite schnell; back/forward funktioniert, weil ich immer die aktualisierte URL schiebe`/blog/calendar-days`Kalender-Highlights kommen aus einem winzigen
- Endpunkt
- Behoben: Datumsbereiche beim Ändern der Sprache/Bestellung fallen gelassen
- Behoben: Kalender nicht erfrischend nach HTMX Swaps oder Themenänderungen

## Server-Caching variiert jetzt durch alle relevanten Abfragetasten

- Was gut funktioniert
- URL-erstes Verhalten: Alle Interaktionen aktualisieren die URL; Sie können Deep-Link zu einem Filterzustand`LinkUrl`Paginierung bewahrt die aktuellen Filter (
- ist auf dem Server eingestellt)

```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 Standardwerte für die aktuellen Abfragewerte, falls vorhanden und Tage mit Posts hervorgehoben werden

### Die Fehler, die ich behoben habe (und neue Features!)

Sichtbarkeit und inhaltliche Kontrolle

- **Die größte Ergänzung: richtiges Post-Opportunity-Management:**Versteckte Pfosten`IsHidden`: Beiträge können nun als versteckt markiert werden (
- **Flagge) und wird nicht in den Listen erscheinen**Geplante Veröffentlichung`ScheduledPublishDate`: Beiträge können eine
- **und erst nach dieser Zeit erscheinen**Gepinnte Pfosten`IsPinned`: Mit gekennzeichnete Stellen

```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);
}
```

### immer zuerst auf Seite 1 erscheinen (großartig für Ankündigungen)

- **Verbesserungen des Datumsbereichs`/blog/date-range`Neu**Endpunkt
- **: Gibt die Min/Max-Termine über alle Beiträge zurück (Sprache-Bewusstsein), so dass der Datumswähler sinnvolle Grenzen setzen kann**Param-Tag-Helfer löschen`<clear-param>`: Hinzugefügt

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

### Tag Helper um Abfrageparameter leicht zu löschen

- Fehlerbehebungen
  - Verlust des Datumsbereichs beim Umschalten der Sprache oder Bestellung`new URL(window.location.href)`Fix: Start von

```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);
});
```

- und überschreiben Sie nur die ändernden Parameter; wenn Flatpickr eine Auswahl hat, wenden Sie sie erneut an.
  
  - Kalender-Highlights nicht erfrischend nach HTMX Swaps`fp.redraw()`Fix: Flatpickr auf init zerstören/erneuern, dann Highlights für den sichtbaren Monat holen und anrufen`htmx:afterSwap`.

- ; auch wieder laufen init auf
  
  - Dark-Modus-Stile, die nicht für den Kalender gelten`<html class>`Fix: beachten`fp.redraw()`und rufen

## wenn es sich ändert.

```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
```

## Wie die Stücke reden

HTMX-Seite Anfrageerkennung`pagerequest`Die Filterleiste verwendet einen benutzerdefinierten

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

Header, um dem Server zu helfen, zwischen ganzseitigen Lasten und teilweisen HTMX Swaps zu unterscheiden:

> **Damit kann der Controller nur die Teilansicht für HTMX-Anfragen und ganze Seitenansichten für die direkte Navigation zurückgeben.**Anmerkung

## : Die Paging Tag Helper Erweiterung und Abfrage Parameter klarer Alpine.js Komponente verdienen ihren eigenen tiefen Tauchgang – ich werde diese im Detail in einem zukünftigen Beitrag über den Bau wiederverwendbarer HTMX/Alpine Komponenten abdecken.

- Noch zu tun
- Schnelle Datumsvoreinstellungen (letzte 7/30 Tage, in diesem Jahr)
- LocalStorage Samen für Sprache

Tastaturunterstützung auf Range Picker