Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Un endpoint per caricare dinamicamente i contenuti con htmx

Creiamo un endpoint che elabori una richiesta via htmx e restituisca il codice HTML per la struttura delle anteprime di una pagina d'archivio
Creiamo un endpoint che elabori una richiesta via htmx e restituisca il codice HTML per la struttura delle anteprime di una pagina d'archivio
Link copiato negli appunti

Creiamo ora un endpoint che elabori una richiesta trasmessa via htmx e restituisca il codice HTML necessario a creare la struttura delle anteprime dei contenuti della pagina di archivio. Il file che costituisce l'endpoint non genera una pagina completa ma produce blocchi di codice HTML.

Il file del frontmatter

Nella cartella /src/pages/archive, creiamo il file load-more.astro e aggiungiamo il seguente frontmatter:

---
export const prerender = false;
import ArticleCard from '../../components/ArticleCard.astro';
import { getCollection } from 'astro:content';
const POSTS_PER_PAGE = 3;
const sortedPosts = (await getCollection('blog')).sort(
	(a, b) => b.data.pubDate.getTime() - a.data.pubDate.getTime()
);
const totalPosts = sortedPosts.length;
const page = Number(new URL(Astro.request.url).searchParams.get('page') || 2);
const start = (page - 1) * POSTS_PER_PAGE;
const end = page * POSTS_PER_PAGE;
const postsToShow = sortedPosts.slice(start, end);
const nextPage = page + 1;
const hasMore = end < totalPosts;
---
Questo codice è in parte uguale al codice del file /scr/pages/archive/index.astro. Per questo commenteremo solo le istruzioni che utilizziamo per la prima volta:

  • export const prerender = false è l'istruzione più importante. Questo dice ad Astro di non generare l'output del file al momento della build, ma al momento della richiesta di rete (SSR). In questo modo si permette ad Astro di leggere i parametri dell'URL (?page=2) che in modalità SSG non sarebbero stati letti.
  • Astro.request è un oggetto disponibile nel frontmatter durante il rendering lato server che rappresenta la richiesta HTTP corrente: Astro.request.url restituisce l'URL completo della richiesta.
  • searchParams.get('page') estrae il valore del parametro page. In questo caso, se non trova il parametro, la condizione lo imposta al valore di fallback 2. Number converte la stringa in un numero.
  • Infine, la logica di paginazione permette di estrarre l'array di post da visualizzare, da start a end.
  • hasMore controlla se ci sono ancora articoli da visualizzare.

Il codice per il markup degli articoli successivi

Di seguito creiamo il codice che, al clic sul pulsante "Carica altri articoli", produce il markup dei successivi POSTS_PER_PAGE articoli:

{postsToShow.length > 0 ? (
	postsToShow.map(post => (
		<ArticleCard post={post} />
	))
) : (
	<p class="text-gray-500 italic text-sm">Nessun articolo disponibile per questa pagina.</p>
)}
<div id="load-more-row" class="mt-12 text-center">
	{hasMore ? (
		<button
			type="button"
			hx-get={`/archive/load-more?page=${nextPage}`}
			hx-target="#load-more-row"
			hx-swap="outerHTML"
			class="bg-blue-600 text-white py-3 px-6 rounded-lg hover:bg-blue-700"
		>
			Altri Articoli
		</button>
	) : (
		<p class="text-gray-500 italic text-sm">Hai visualizzato tutti gli articoli!</p>
	)}
</div>

Ecco cosa fa questo codice:

  • postsToShow.map(...) genera i nuovi articoli.
  • La div#load-more-row ha lo stesso id del container del pulsante originale perché abbiamo assegnato all'attributo hx-swap il valore outerHTML che fa sì che l'output dell'endpoint vada a sostituire del tutto la div container.
  • Il rendering condizionale (hasMore) fa sì che, se ci sono altri articoli da visualizzare, venga generato un nuovo pulsante, altrimenti sarà generata la stringa "Hai visualizzato tutti gli articoli!".
  • Abbiamo aggiunto il parametro page alla query string dell'URL della richiesta. Nel file index.astro avevamo invece utilizzato l'attributo hx-vals. Le due soluzioni sono equivalenti.

Utilizzo congiunto di Alpine e htmx

Negli esempi sopra riportati abbiamo impostato in modo forzoso la proprietà page assegnandole il valore 2. È una soluzione non ottimale quando si lavora con htmx, ma possiamo rendere più elegante il nostro codice utilizzando lo stato di Alpine.

Apriamo il file /src/pages/archive/index.astro e rimuoviamo dal pulsante l'attributo hx-val:

<button
	type="button"
	hx-get="/archive/load-more"
	hx-target="#load-more-row"
	hx-swap="outerHTML"
	class="bg-blue-600 text-white py-3 px-6 rounded-lg hover:bg-blue-700"
>

Salviamo il file e apriamo /src/pages/archive/load-more.astro. Qui utilizziamo la direttiva x-data di Alpine per memorizzare lo stato iniziale dell'applicazione:

<div x-data="{ page: 2 }" id="load-more-row" class="mt-12 text-center">

Quindi aggiungiamo la direttiva @click (forma abbreviata di x-on:click) al pulsante:

<button
	type="button"
	hx-get={`/archive/load-more?page=${nextPage}`}
	hx-target="#load-more-row"
	hx-swap="outerHTML"
	@click="page += 1"
	class="bg-blue-600 text-white py-3 px-6 rounded-lg hover:bg-blue-700"
>

È ora di provare il codice. Avviamo il server di sviluppo con npm run dev e carichiamo articoli finché non abbiamo esaurito tutti i contenuti. Il codice descritto fino ad ora è disponibile in questa repo su GitHub. Il nostro lavoro con Alpine, Astro e htmx non è però ancora finito.

Se vuoi aggiornamenti su Un endpoint per caricare dinamicamente i contenuti con htmx inserisci la tua email nel box qui sotto:

Compilando il presente form acconsento a ricevere le informazioni relative ai servizi di cui alla presente pagina ai sensi dell'informativa sulla privacy.

Ti consigliamo anche