Lo Stato è l'insieme dei dati che determinano il comportamento e l'aspetto di un componente di Alpine.js. In pratica, lo Stato è costituito dall'insieme delle variabili che memorizzano informazioni che cambiano in modo reattivo con l'interazione dell'utente. Ogni volta che l'utente esegue operazioni che cambiano lo stato, Alpine.js aggiorna automaticamente il DOM.
È possibile rendere disponibili i dati a livello locale o globale. Si parla così di local state e global store. I dati disponibili a livello locale sono accessibili solo all'interno di una determinata sezione di HTML (un componente Alpine) e non influenzano altre parti della pagina. Per fornire dati locali ad un blocco HTML si usa la direttiva x-data
. Vediamo come accedere ai dati a livello locale con degli esempi pratici.
Il local state di Alpine.js
Alpine.js consente di dichiarare lo stato di un blocco HTML in un singolo attributo x-data
. La documentazione recita testualmente:
Everything in Alpine starts with the
x-data
directive.
Con l'attributo x-data
, un frammento di HTML definisce un componente Alpine. Ecco un esempio:
<div x-data="{ count: 0 }">
<button x-on:click="count++">Increment</button>
<span x-text="count"></span>
</div>
Nell'esempio qui sopra,
x-data
indica ad Alpine.js che ladiv
e tutti gli elementi contenuti costituiscono un componente Alpine;{ count: 0 }
definisce un oggetto JSON che rappresenta lo stato iniziale del componente. In questo caso abbiamo solo la proprietàcount
che viene inizializzata a0
.
La direttiva x-data
fornisce, quindi, i dati reattivi a cui il componente deve fare riferimento, definiti come proprietà di un oggetto JavaScript. Le proprietà così definite sono disponibili a tutti gli elementi contenuti nel componente Alpine.
In quest'altro esempio, la proprietà today
contiene una "arrow function":
<div x-data="{ today: () => new Date().toLocaleDateString() }">
<span x-text="today()"></span>
</div>
x-data
viene valutato come un normale oggetto JavaScript. In quanto tale, oltre alle normali proprietà, può contenere metodi e getter. Nell'esempio che segue, il metodo toggle
viene eseguito ogni volta che un utente fa clic sul pulsante:
<div x-data="{ show: false, toggle() { this.show = ! this.show } }">
<button @click="toggle()">Toggle</button>
<div x-show="show" x-transition.duration.500ms>
Hello 👋
</div>
</div>
Si noti che abbiamo utilizzato this
per accedere allo stato sullo stesso oggetto.
Infine, quando l'unico scopo è quello di restituire dati derivati da altre proprietà dello stato, possiamo utilizzare una funzione che si comporta in modo simile ad un getter.
<div x-data="{
firstName: 'Mario',
lastName: 'Rossi',
get fullName() { return `${this.firstName} ${this.lastName}`; }
}">
<p>Nome completo: <span x-text="fullName"></span></p>
</div>
get fullName()
definisce la proprietà fullName
, il cui valore è una funzione. La funzione restituisce la stringa risultante dalla concatenazione dei valori delle proprietà firstName
e lastName
, a cui accede tramite la keyword this
.
La funzione, inoltre, aggiorna il valore calcolato ogni volta che questo viene modificato. Ad esempio, potremmo aggiungere due campi per permettere all'utente di cambiare il nome predefinito:
<div x-data="{
firstName: 'Mario',
lastName: 'Rossi',
get fullName() { return `${this.firstName} ${this.lastName}`; }
}">
<p>Nome completo: <span x-text="fullName"></span></p>
<input type="text" x-model="firstName" placeholder="Nome">
<input type="text" x-model="lastName" placeholder="Cognome">
</div>
La direttiva x-model
aggancia il valore del campo di testo alle corrispondenti proprietà di x-data
. In questo modo i dati cambiano in modo interattivo all'input dell'utente.
Negli esempi precedenti, abbiamo sempre utilizzato x-data
con una div
. Quando un componente contiene un solo elemento è possibile assegnare la direttiva x-data
a quell'unico elemento, senza utilizzare un elemento contenitore.
<button x-data="{ count: 0 }" x-on:click="count++" x-text="`Hai cliccato ${count} volte`"></button>
La proprietà Alpine.data
Alpine.data
è una proprietà di Alpine.js che permette di spostare logica e dati dall'attributo x-data
ad un template esterno in modo che possano essere riutilizzati. Potremmo, ad esempio, modificare il codice dell'esempio precedente come segue:
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('persona', () => ({
firstName: 'Mario',
lastName: 'Rossi',
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}));
});
</script>
<div x-data="persona">
<p>Nome completo: <span x-text="fullName"></span></p>
<input type="text" x-model="firstName" placeholder="Nome">
<input type="text" x-model="lastName" placeholder="Cognome">
</div>
In questo esempio abbiamo fatto riferimento al provider di Alpine.js con il nome persona
. È possibile anche invocare il provider con persona()
in modo da instanziare il componente con i parametri specificati. Ad esempio:
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('persona', (name, surname) => ({
firstName: name,
lastName: surname,
fullName() {
return `${this.firstName} ${this.lastName}`;
}
}));
});
</script>
<div x-data="persona('Roberto', 'Bianchi')">
<p>Nome completo: <span x-text="fullName"></span></p>
<input type="text" x-model="firstName" placeholder="Nome">
<input type="text" x-model="lastName" placeholder="Cognome">
</div>
<div x-data="persona('Giuseppe', 'Verdi')">
<p>Nome completo: <span x-text="fullName"></span></p>
<input type="text" x-model="firstName" placeholder="Nome">
<input type="text" x-model="lastName" placeholder="Cognome">
</div>
In questo esempio document.addEventListener('alpine:init', () => { ... });
aggiunge un event listener che dice al browser di ascoltare l'evento alpine:init
. Questo evento viene emesso da Alpine.js quando la libreria è stata completamente caricata e inizializzata, ma prima che Alpine inizi a cercare e inizializzare i componenti nella pagina. In questo modo, l'oggetto Alpine.data
sarà disponibile prima che Alpine cominci a lavorare sul DOM. Si noti che alpine:init
viene eseguito una sola volta.
Ora possiamo riutilizzare l'oggetto persona
più volte nella stessa pagina, passando ogni volta parametri diversi.