# Filterrad: Framsteg, fel och små vinster

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

## Inledning

Jag har satt ihop en riktig filter bar för blogglistan: språk, datumintervall, sortera, och pagination som förblir snappy med HTMX.

Det är nära nu-men som alltid, de sista 20% är den kryddiga biten: datum, caches, och varför fungerar det lokalt men inte efter ett byte?[Om du vill ha en djupdykning med massor av kod och diagram, se:](/blog/filterbarprogressandissues)

> /blog/filterbarprogression och frågor

[TOC]

## Kom ihåg att denna webbplats är ett pågående arbete, denna typ av saker kommer att hända när du äter-din-egna-hundmat!

- TL;DR
- Ny filterrad: Språk + Sortera + Datumintervall
- HTMX partiella swappar håller sidan snabbt; tillbaka/framåt fungerar eftersom jag alltid trycker på den uppdaterade webbadressen`/blog/calendar-days`Kalenderns höjdpunkter kommer från ett litet
- ändpunkt
- Fast: datumintervall som tappas när språket/beställningen ändras
- Fast: kalender inte uppfriskande efter HTMX-byten eller temaändringar

## Server caching nu varierar med alla relevanta frågetangenter

- Vad fungerar bra
- URL-första beteende: Alla interaktioner uppdaterar webbadressen; du kan djuplänka till ett filtertillstånd`LinkUrl`Paginering bevarar de aktuella filtren (
- är inställd på servern)

```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 intervall standardvärden för aktuella frågevärden om närvarande och markerar dagar med inlägg

### Felen jag fixade (och nya funktioner!)

Synlighet och innehållskontroll

- **Den största additionen: korrekt hantering av tjänstens synlighet:**Dolda inlägg`IsHidden`: Inlägg kan nu markeras som dolda (
- **flagga) och kommer inte att visas i listor**Schemalagd publicering`ScheduledPublishDate`: Poster kan ha en
- **och endast visas efter den tiden**Fastsatta tjänster`IsPinned`: Inlägg markerade med

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

### visas alltid först på sidan 1 (bra för tillkännagivanden)

- **Förbättringar av datumintervall`/blog/date-range`Nytt**ändpunkt
- **: Returnerar min/max datum över alla inlägg (språk-medveten) så datumväljaren kan ställa in förnuftiga gränser**Rensa param tag helper`<clear-param>`Tillagd:

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

### tag helper för att enkelt rensa frågeparametrar

- Felrättningar
  - Förlora datumintervall vid byte av språk eller order`new URL(window.location.href)`Rättning: Börja från

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

- och åsidosätter endast de föränderliga paramerna; om Flatpickr har ett urval, applicera det på nytt.
  
  - Kalenderns höjdpunkter är inte uppfriskande efter HTMX-byten`fp.redraw()`Rättning: Förstör/återskapa Flatpicker på init, hämta sedan höjdpunkter för den synliga månaden och ring`htmx:afterSwap`.

- ; även re-run init on
  
  - Mörka stilar som inte gäller för kalendern`<html class>`Rättning: observera`fp.redraw()`och ring

## När det förändras.

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

## Hur bitarna talar

Detektion av HTMX- sidförfrågan`pagerequest`Filterraden använder en anpassad

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

Rubrik för att hjälpa servern att skilja mellan helsidesbelastningar och partiella HTMX-byten:

> **Detta gör det möjligt för regulatorn att returnera bara delvyn för HTMX-förfrågningar och helsidesvyer för direkt navigering.**Anmärkning

## : Peging tag helper extension och frågeparameter klarare Alpine.js komponent förtjänar sin egen djupa dyk – Jag ska täcka dessa i detalj i ett kommande inlägg om att bygga återanvändbara HTMX / Alpine komponenter.

- Det gör jag fortfarande.
- Snabbdatum förinställningar (senast 7/30 dagar, Detta år)
- LocalStorage frö för språk

Tangentbordsstöd för avståndsväljare